From 897c1ff562c734fb87f1399e5c88c13bc05083f9 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 11:01:09 +0200 Subject: [PATCH 001/141] feat: add database dependencies for JPA, Hibernate, and Flyway --- gradle/libs.versions.toml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6e083a7c70..e6e96b17ad 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -32,6 +32,14 @@ informative-annotations = "1.6" vault = "1.7.1" serverlib = "2.3.7" +# Database +jpa-api = "3.2.0" +hibernate-core = "7.1.0.Final" +flyway-core = "11.11.2" +# JDBC Drivers +mariadb-java-client = "3.5.5" +sqlite-jdbc = "3.50.3.0" + # Gradle plugins shadow = "8.3.9" grgit = "4.1.1" @@ -77,6 +85,14 @@ paperlib = { group = "io.papermc", name = "paperlib", version.ref = "paperlib" } vault = { group = "com.github.MilkBowl", name = "VaultAPI", version.ref = "vault" } serverlib = { group = "dev.notmyfault.serverlib", name = "ServerLib", version.ref = "serverlib" } +# Database +jpaApi = { group = "jakarta.persistence", name = "jakarta.persistence-api", version.ref = "jpa-api" } +hibernateCore = { group = "org.hibernate.orm", name = "hibernate-core", version.ref = "hibernate-core" } +flywayCore = { group = "org.flywaydb", name = "flyway-core", version.ref = "flyway-core" } +# JDBC Drivers +mariadbJavaClient = { group = "org.mariadb.jdbc", name = "mariadb-java-client", version.ref = "mariadb-java-client" } +sqliteJdbc = { group = "org.xerial", name = "sqlite-jdbc", version.ref = "sqlite-jdbc" } + [plugins] shadow = { id = "com.gradleup.shadow", version.ref = "shadow" } grgit = { id = "org.ajoberstar.grgit", version.ref = "grgit" } From a843e53bb72c210e81933d95824ee139b0bc86ce Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 11:01:16 +0200 Subject: [PATCH 002/141] feat: add Hibernate, JPA, and Flyway dependencies for database integration --- Core/build.gradle.kts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Core/build.gradle.kts b/Core/build.gradle.kts index 5b7367be0a..6225359585 100644 --- a/Core/build.gradle.kts +++ b/Core/build.gradle.kts @@ -44,6 +44,14 @@ dependencies { api(libs.arkitektonika) api(libs.paster) api(libs.informativeAnnotations) + + // Database + api(libs.hibernateCore) + api(libs.jpaApi) + api(libs.flywayCore) + + runtimeOnly(libs.mariadbJavaClient) + runtimeOnly(libs.sqliteJdbc) } tasks.processResources { From 517a46a389a71bd512953bfbb85a05df47cfb079 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 12:09:32 +0200 Subject: [PATCH 003/141] feat: add PlotEntity class for database representation of plots --- .../core/persistence/entity/PlotEntity.java | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/entity/PlotEntity.java diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotEntity.java new file mode 100644 index 0000000000..19b77a9ed5 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotEntity.java @@ -0,0 +1,98 @@ +package com.plotsquared.core.persistence.entity; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; + +@Entity +@Table(name = "plot") +@NamedQueries({ + @NamedQuery(name = "Plot.findByWorldAndId", query = "SELECT p FROM PlotEntity p WHERE p.world = :world AND p.plotIdX = :x AND p.plotIdZ = :z"), + @NamedQuery(name = "Plot.findByOwner", query = "SELECT p FROM PlotEntity p WHERE p.owner = :owner"), + @NamedQuery(name = "Plot.findByWorld", query = "SELECT p FROM PlotEntity p WHERE p.world = :world") +}) +public class PlotEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name = "plot_id_x", nullable = false) + private int plotIdX; + @Column(name = "plot_id_z", nullable = false) + private int plotIdZ; + @Column(length = 40, nullable = false) + private String owner; + @Column(length = 45, nullable = false) + private String world; + @Column(name = "timestamp", insertable = false, updatable = false) + private java.sql.Timestamp timestamp; + + @OneToOne(mappedBy = "plot", cascade = CascadeType.ALL, optional = true, fetch = FetchType.LAZY) + private PlotSettingsEntity settings; + + public PlotEntity() { + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public int getPlotIdX() { + return plotIdX; + } + + public void setPlotIdX(int plotIdX) { + this.plotIdX = plotIdX; + } + + public int getPlotIdZ() { + return plotIdZ; + } + + public void setPlotIdZ(int plotIdZ) { + this.plotIdZ = plotIdZ; + } + + public String getOwner() { + return owner; + } + + public void setOwner(String owner) { + this.owner = owner; + } + + public String getWorld() { + return world; + } + + public void setWorld(String world) { + this.world = world; + } + + public java.sql.Timestamp getTimestamp() { + return timestamp; + } + + public void setTimestamp(java.sql.Timestamp timestamp) { + this.timestamp = timestamp; + } + + public PlotSettingsEntity getSettings() { + return settings; + } + + public void setSettings(PlotSettingsEntity settings) { + this.settings = settings; + } +} From e258786b448cf56b59f6552e5c60455eb31fcf78 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 12:10:45 +0200 Subject: [PATCH 004/141] feat: add ClusterEntity class for database representation of clusters --- .../persistence/entity/ClusterEntity.java | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterEntity.java diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterEntity.java new file mode 100644 index 0000000000..6a774a2d91 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterEntity.java @@ -0,0 +1,48 @@ +package com.plotsquared.core.persistence.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; + +@Entity +@Table(name = "cluster") +@NamedQueries({ + @NamedQuery(name = "Cluster.findByWorldAndBounds", query = "SELECT c FROM ClusterEntity c WHERE c.world = :world AND c.pos1X <= :x AND c.pos2X >= :x AND c.pos1Z <= :z AND c.pos2Z >= :z") +}) +public class ClusterEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name = "pos1_x") private int pos1X; + @Column(name = "pos1_z") private int pos1Z; + @Column(name = "pos2_x") private int pos2X; + @Column(name = "pos2_z") private int pos2Z; + @Column(length = 40) private String owner; + @Column(length = 45) private String world; + @Column(name = "timestamp", insertable = false, updatable = false) + private java.sql.Timestamp timestamp; + + public ClusterEntity() {} + + public Long getId() { return id; } + public void setId(Long id) { this.id = id; } + public int getPos1X() { return pos1X; } + public void setPos1X(int pos1X) { this.pos1X = pos1X; } + public int getPos1Z() { return pos1Z; } + public void setPos1Z(int pos1Z) { this.pos1Z = pos1Z; } + public int getPos2X() { return pos2X; } + public void setPos2X(int pos2X) { this.pos2X = pos2X; } + public int getPos2Z() { return pos2Z; } + public void setPos2Z(int pos2Z) { this.pos2Z = pos2Z; } + public String getOwner() { return owner; } + public void setOwner(String owner) { this.owner = owner; } + public String getWorld() { return world; } + public void setWorld(String world) { this.world = world; } + public java.sql.Timestamp getTimestamp() { return timestamp; } + public void setTimestamp(java.sql.Timestamp timestamp) { this.timestamp = timestamp; } +} From 76414fb7a1b4dae14537833c4d2d0188ed8b7af3 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 12:10:56 +0200 Subject: [PATCH 005/141] feat: add PlotUserId class for composite key representation in database --- .../core/persistence/entity/PlotUserId.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/entity/PlotUserId.java diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotUserId.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotUserId.java new file mode 100644 index 0000000000..c6cc88d01d --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotUserId.java @@ -0,0 +1,34 @@ +package com.plotsquared.core.persistence.entity; + +import java.io.Serializable; +import java.util.Objects; + +public class PlotUserId implements Serializable { + private Long plotId; + private String userUuid; + + public PlotUserId() {} + + public PlotUserId(Long plotId, String userUuid) { + this.plotId = plotId; + this.userUuid = userUuid; + } + + public Long getPlotId() { return plotId; } + public void setPlotId(Long plotId) { this.plotId = plotId; } + public String getUserUuid() { return userUuid; } + public void setUserUuid(String userUuid) { this.userUuid = userUuid; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PlotUserId that = (PlotUserId) o; + return Objects.equals(plotId, that.plotId) && Objects.equals(userUuid, that.userUuid); + } + + @Override + public int hashCode() { + return Objects.hash(plotId, userUuid); + } +} From b472442da3e527f9d5e28e264f74d21cf8215d5e Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 12:11:02 +0200 Subject: [PATCH 006/141] feat: add PlotRatingId class for composite key representation in database --- .../core/persistence/entity/PlotRatingId.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/entity/PlotRatingId.java diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotRatingId.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotRatingId.java new file mode 100644 index 0000000000..190cf90888 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotRatingId.java @@ -0,0 +1,34 @@ +package com.plotsquared.core.persistence.entity; + +import java.io.Serializable; +import java.util.Objects; + +public class PlotRatingId implements Serializable { + private Long plotId; + private String player; + + public PlotRatingId() {} + + public PlotRatingId(Long plotId, String player) { + this.plotId = plotId; + this.player = player; + } + + public Long getPlotId() { return plotId; } + public void setPlotId(Long plotId) { this.plotId = plotId; } + public String getPlayer() { return player; } + public void setPlayer(String player) { this.player = player; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PlotRatingId that = (PlotRatingId) o; + return Objects.equals(plotId, that.plotId) && Objects.equals(player, that.player); + } + + @Override + public int hashCode() { + return Objects.hash(plotId, player); + } +} From 785f3d12576264d3a515303622c655be0fa906ee Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 12:11:13 +0200 Subject: [PATCH 007/141] feat: add ClusterUserId class for composite key representation in database --- .../persistence/entity/ClusterUserId.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterUserId.java diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterUserId.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterUserId.java new file mode 100644 index 0000000000..fff1d45b05 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterUserId.java @@ -0,0 +1,34 @@ +package com.plotsquared.core.persistence.entity; + +import java.io.Serializable; +import java.util.Objects; + +public class ClusterUserId implements Serializable { + private Long clusterId; + private String userUuid; + + public ClusterUserId() {} + + public ClusterUserId(Long clusterId, String userUuid) { + this.clusterId = clusterId; + this.userUuid = userUuid; + } + + public Long getClusterId() { return clusterId; } + public void setClusterId(Long clusterId) { this.clusterId = clusterId; } + public String getUserUuid() { return userUuid; } + public void setUserUuid(String userUuid) { this.userUuid = userUuid; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ClusterUserId that = (ClusterUserId) o; + return Objects.equals(clusterId, that.clusterId) && Objects.equals(userUuid, that.userUuid); + } + + @Override + public int hashCode() { + return Objects.hash(clusterId, userUuid); + } +} From 498740ee0a53a685e221d8beedf3d3dae637b154 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 12:11:21 +0200 Subject: [PATCH 008/141] feat: add PlotCommentId class for composite key representation in database --- .../persistence/entity/PlotCommentId.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/entity/PlotCommentId.java diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotCommentId.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotCommentId.java new file mode 100644 index 0000000000..d38d863725 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotCommentId.java @@ -0,0 +1,38 @@ +package com.plotsquared.core.persistence.entity; + +import java.io.Serializable; +import java.util.Objects; + +public class PlotCommentId implements Serializable { + private String world; + private Integer hashcode; + private String inbox; + + public PlotCommentId() {} + + public PlotCommentId(String world, Integer hashcode, String inbox) { + this.world = world; + this.hashcode = hashcode; + this.inbox = inbox; + } + + public String getWorld() { return world; } + public void setWorld(String world) { this.world = world; } + public Integer getHashcode() { return hashcode; } + public void setHashcode(Integer hashcode) { this.hashcode = hashcode; } + public String getInbox() { return inbox; } + public void setInbox(String inbox) { this.inbox = inbox; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PlotCommentId that = (PlotCommentId) o; + return Objects.equals(world, that.world) && Objects.equals(hashcode, that.hashcode) && Objects.equals(inbox, that.inbox); + } + + @Override + public int hashCode() { + return Objects.hash(world, hashcode, inbox); + } +} From b9d04ff8c894d189c5baedac34a5d3ea8dd74fef Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 12:11:31 +0200 Subject: [PATCH 009/141] feat: add PlotSettingsEntity class for database representation of plot settings --- .../entity/PlotSettingsEntity.java | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/entity/PlotSettingsEntity.java diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotSettingsEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotSettingsEntity.java new file mode 100644 index 0000000000..4e7a5f0dc5 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotSettingsEntity.java @@ -0,0 +1,71 @@ +package com.plotsquared.core.persistence.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.MapsId; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; + +@Entity +@Table(name = "plot_settings") +public class PlotSettingsEntity { + @Id + @Column(name = "plot_plot_id") + private Long id; + + @OneToOne + @MapsId + @JoinColumn(name = "plot_plot_id") + private PlotEntity plot; + + @Column(length = 45) + private String biome; + @Column(name = "rain") + private Integer rain; + @Column(name = "custom_time") + private Boolean customTime; + @Column(name = "time") + private Integer time; + @Column(name = "deny_entry") + private Boolean denyEntry; + @Column(length = 50) + private String alias; + @Column(name = "merged") + private Integer merged; + @Column(length = 50) + private String position; + + public PlotSettingsEntity() {} + + public Long getId() { return id; } + public void setId(Long id) { this.id = id; } + + public PlotEntity getPlot() { return plot; } + public void setPlot(PlotEntity plot) { this.plot = plot; } + + public String getBiome() { return biome; } + public void setBiome(String biome) { this.biome = biome; } + + public Integer getRain() { return rain; } + public void setRain(Integer rain) { this.rain = rain; } + + public Boolean getCustomTime() { return customTime; } + public void setCustomTime(Boolean customTime) { this.customTime = customTime; } + + public Integer getTime() { return time; } + public void setTime(Integer time) { this.time = time; } + + public Boolean getDenyEntry() { return denyEntry; } + public void setDenyEntry(Boolean denyEntry) { this.denyEntry = denyEntry; } + + public String getAlias() { return alias; } + public void setAlias(String alias) { this.alias = alias; } + + public Integer getMerged() { return merged; } + public void setMerged(Integer merged) { this.merged = merged; } + + public String getPosition() { return position; } + public void setPosition(String position) { this.position = position; } +} From 6e5464efb3565be6a0d5cc706cb8bfd64e214377 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 12:11:42 +0200 Subject: [PATCH 010/141] feat: add ClusterSettingsEntity class for database representation of cluster settings --- .../entity/ClusterSettingsEntity.java | 122 ++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterSettingsEntity.java diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterSettingsEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterSettingsEntity.java new file mode 100644 index 0000000000..d4474b4f61 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterSettingsEntity.java @@ -0,0 +1,122 @@ +package com.plotsquared.core.persistence.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.MapsId; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; + +@Entity +@Table(name = "cluster_settings") +public class ClusterSettingsEntity { + @Id + @Column(name = "cluster_id") + private Long id; + + @OneToOne + @MapsId + @JoinColumn(name = "cluster_id") + private ClusterEntity cluster; + + @Column(length = 45) + private String biome; + @Column(name = "rain") + private Integer rain; + @Column(name = "custom_time") + private Boolean customTime; + @Column(name = "time") + private Integer time; + @Column(name = "deny_entry") + private Boolean denyEntry; + @Column(length = 50) + private String alias; + @Column(name = "merged") + private Integer merged; + @Column(length = 50) + private String position; + + public ClusterSettingsEntity() { + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public ClusterEntity getCluster() { + return cluster; + } + + public void setCluster(ClusterEntity cluster) { + this.cluster = cluster; + } + + public String getBiome() { + return biome; + } + + public void setBiome(String biome) { + this.biome = biome; + } + + public Integer getRain() { + return rain; + } + + public void setRain(Integer rain) { + this.rain = rain; + } + + public Boolean getCustomTime() { + return customTime; + } + + public void setCustomTime(Boolean customTime) { + this.customTime = customTime; + } + + public Integer getTime() { + return time; + } + + public void setTime(Integer time) { + this.time = time; + } + + public Boolean getDenyEntry() { + return denyEntry; + } + + public void setDenyEntry(Boolean denyEntry) { + this.denyEntry = denyEntry; + } + + public String getAlias() { + return alias; + } + + public void setAlias(String alias) { + this.alias = alias; + } + + public Integer getMerged() { + return merged; + } + + public void setMerged(Integer merged) { + this.merged = merged; + } + + public String getPosition() { + return position; + } + + public void setPosition(String position) { + this.position = position; + } +} From dcccbed9b64c3ebfdb839dcc2155b7c736d73ba1 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 12:12:11 +0200 Subject: [PATCH 011/141] feat: add PlotMembershipEntity class for database representation of plot memberships --- .../entity/PlotMembershipEntity.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/entity/PlotMembershipEntity.java diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotMembershipEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotMembershipEntity.java new file mode 100644 index 0000000000..dae514f873 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotMembershipEntity.java @@ -0,0 +1,31 @@ +package com.plotsquared.core.persistence.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; + +@Entity +@Table(name = "plot_helpers") +@IdClass(PlotUserId.class) +@NamedQueries({ + @NamedQuery(name = "PlotHelper.delete", query = "DELETE FROM PlotMembershipEntity e WHERE e.plotId = :plotId AND e.userUuid = :uuid"), + @NamedQuery(name = "PlotHelper.findUsers", query = "SELECT e.userUuid FROM PlotMembershipEntity e WHERE e.plotId = :plotId") +}) +public class PlotMembershipEntity { + @Id + @Column(name = "plot_plot_id") + private Long plotId; + @Id @Column(name = "user_uuid", length = 40) + private String userUuid; + + public PlotMembershipEntity() {} + + public Long getPlotId() { return plotId; } + public void setPlotId(Long plotId) { this.plotId = plotId; } + public String getUserUuid() { return userUuid; } + public void setUserUuid(String userUuid) { this.userUuid = userUuid; } +} From b0d20a497de400571cf7a66244498efb65d17185 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 12:12:18 +0200 Subject: [PATCH 012/141] feat: add PlotTrustedEntity class for database representation of trusted plots --- .../persistence/entity/PlotTrustedEntity.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/entity/PlotTrustedEntity.java diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotTrustedEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotTrustedEntity.java new file mode 100644 index 0000000000..1c0b891ac6 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotTrustedEntity.java @@ -0,0 +1,31 @@ +package com.plotsquared.core.persistence.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; + +@Entity +@Table(name = "plot_trusted") +@IdClass(PlotUserId.class) +@NamedQueries({ + @NamedQuery(name = "PlotTrusted.delete", query = "DELETE FROM PlotTrustedEntity e WHERE e.plotId = :plotId AND e.userUuid = :uuid"), + @NamedQuery(name = "PlotTrusted.findUsers", query = "SELECT e.userUuid FROM PlotTrustedEntity e WHERE e.plotId = :plotId") +}) +public class PlotTrustedEntity { + @Id + @Column(name = "plot_plot_id") + private Long plotId; + @Id @Column(name = "user_uuid", length = 40) + private String userUuid; + + public PlotTrustedEntity() {} + + public Long getPlotId() { return plotId; } + public void setPlotId(Long plotId) { this.plotId = plotId; } + public String getUserUuid() { return userUuid; } + public void setUserUuid(String userUuid) { this.userUuid = userUuid; } +} From e356e9fba963f43dcbc19788d26657f7ee946cbe Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 12:12:33 +0200 Subject: [PATCH 013/141] feat: add PlotDeniedEntity class for database representation of denied plots --- .../persistence/entity/PlotDeniedEntity.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/entity/PlotDeniedEntity.java diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotDeniedEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotDeniedEntity.java new file mode 100644 index 0000000000..6b956d861e --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotDeniedEntity.java @@ -0,0 +1,31 @@ +package com.plotsquared.core.persistence.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; + +@Entity +@Table(name = "plot_denied") +@IdClass(PlotUserId.class) +@NamedQueries({ + @NamedQuery(name = "PlotDenied.delete", query = "DELETE FROM PlotDeniedEntity e WHERE e.plotId = :plotId AND e.userUuid = :uuid"), + @NamedQuery(name = "PlotDenied.findUsers", query = "SELECT e.userUuid FROM PlotDeniedEntity e WHERE e.plotId = :plotId") +}) +public class PlotDeniedEntity { + @Id + @Column(name = "plot_plot_id") + private Long plotId; + @Id @Column(name = "user_uuid", length = 40) + private String userUuid; + + public PlotDeniedEntity() {} + + public Long getPlotId() { return plotId; } + public void setPlotId(Long plotId) { this.plotId = plotId; } + public String getUserUuid() { return userUuid; } + public void setUserUuid(String userUuid) { this.userUuid = userUuid; } +} From 5b0d563752fbb736c418c265781daa8e26786268 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 12:12:58 +0200 Subject: [PATCH 014/141] feat: add PlotCommentEntity class for database representation of plot comments --- .../persistence/entity/PlotCommentEntity.java | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/entity/PlotCommentEntity.java diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotCommentEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotCommentEntity.java new file mode 100644 index 0000000000..7c8608288e --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotCommentEntity.java @@ -0,0 +1,49 @@ +package com.plotsquared.core.persistence.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; + +@Entity +@Table(name = "plot_comments") +@IdClass(PlotCommentId.class) +@NamedQueries({ + @NamedQuery(name = "PlotComment.findByWorldAndInbox", query = "SELECT c FROM PlotCommentEntity c WHERE c.world = :world AND c.inbox = :inbox ORDER BY c.timestamp DESC"), + @NamedQuery(name = "PlotComment.deleteOne", query = "DELETE FROM PlotCommentEntity c WHERE c.world = :world AND c.hashcode = :hash AND c.inbox = :inbox AND c.sender = :sender"), + @NamedQuery(name = "PlotComment.clearInbox", query = "DELETE FROM PlotCommentEntity c WHERE c.world = :world AND c.inbox = :inbox") +}) +public class PlotCommentEntity { + @Id + @Column(length = 40) + private String world; + @Id @Column(name = "hashcode") + private Integer hashcode; + @Id @Column(length = 40) + private String inbox; + + @Column(length = 40, nullable = false) + private String comment; + @Column(name = "timestamp", nullable = false) + private Integer timestamp; + @Column(length = 40, nullable = false) + private String sender; + + public PlotCommentEntity() {} + + public String getWorld() { return world; } + public void setWorld(String world) { this.world = world; } + public Integer getHashcode() { return hashcode; } + public void setHashcode(Integer hashcode) { this.hashcode = hashcode; } + public String getInbox() { return inbox; } + public void setInbox(String inbox) { this.inbox = inbox; } + public String getComment() { return comment; } + public void setComment(String comment) { this.comment = comment; } + public Integer getTimestamp() { return timestamp; } + public void setTimestamp(Integer timestamp) { this.timestamp = timestamp; } + public String getSender() { return sender; } + public void setSender(String sender) { this.sender = sender; } +} From d7a8842034dd347a8fa2b7f858c8a6f549d49094 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 12:13:08 +0200 Subject: [PATCH 015/141] feat: add PlotRatingEntity class for database representation of plot ratings --- .../persistence/entity/PlotRatingEntity.java | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/entity/PlotRatingEntity.java diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotRatingEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotRatingEntity.java new file mode 100644 index 0000000000..5bc665d630 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotRatingEntity.java @@ -0,0 +1,36 @@ +package com.plotsquared.core.persistence.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; + +@Entity +@Table(name = "plot_rating") +@IdClass(PlotRatingId.class) +@NamedQueries({ + @NamedQuery(name = "PlotRating.findByPlot", query = "SELECT r FROM PlotRatingEntity r WHERE r.plotId = :plotId"), + @NamedQuery(name = "PlotRating.upsert", query = "UPDATE PlotRatingEntity r SET r.rating = :rating WHERE r.plotId = :plotId AND r.player = :player"), + @NamedQuery(name = "PlotRating.updateValue", query = "UPDATE PlotRatingEntity r SET r.rating = :rating WHERE r.plotId = :plotId AND r.player = :player") +}) +public class PlotRatingEntity { + @Id @Column(name = "plot_plot_id") + private Long plotId; + @Id + @Column(length = 40) + private String player; + @Column(nullable = false) + private Integer rating; + + public PlotRatingEntity() {} + + public Long getPlotId() { return plotId; } + public void setPlotId(Long plotId) { this.plotId = plotId; } + public String getPlayer() { return player; } + public void setPlayer(String player) { this.player = player; } + public Integer getRating() { return rating; } + public void setRating(Integer rating) { this.rating = rating; } +} From 226273cec4edf9995f9a925530fab949d0f6b752 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 12:13:21 +0200 Subject: [PATCH 016/141] feat: add ClusterHelperEntity class for database representation of cluster helpers --- .../entity/ClusterHelperEntity.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterHelperEntity.java diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterHelperEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterHelperEntity.java new file mode 100644 index 0000000000..8daa100b3e --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterHelperEntity.java @@ -0,0 +1,32 @@ +package com.plotsquared.core.persistence.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; + +@Entity +@Table(name = "cluster_helpers") +@IdClass(ClusterUserId.class) +@NamedQueries({ + @NamedQuery(name = "ClusterHelper.delete", query = "DELETE FROM ClusterHelperEntity e WHERE e.clusterId = :clusterId AND e.userUuid = :uuid"), + @NamedQuery(name = "ClusterHelper.findUsers", query = "SELECT e.userUuid FROM ClusterHelperEntity e WHERE e.clusterId = :clusterId") +}) +public class ClusterHelperEntity { + @Id + @Column(name = "cluster_id") + private Long clusterId; + @Id + @Column(name = "user_uuid", length = 40) + private String userUuid; + + public ClusterHelperEntity() {} + + public Long getClusterId() { return clusterId; } + public void setClusterId(Long clusterId) { this.clusterId = clusterId; } + public String getUserUuid() { return userUuid; } + public void setUserUuid(String userUuid) { this.userUuid = userUuid; } +} From d5d7b04c718865b85f49c83e67d59cd7c606b624 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 12:13:35 +0200 Subject: [PATCH 017/141] feat: add ClusterInvitedEntity class for database representation of invited cluster users --- .../entity/ClusterInvitedEntity.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterInvitedEntity.java diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterInvitedEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterInvitedEntity.java new file mode 100644 index 0000000000..81ff877a97 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterInvitedEntity.java @@ -0,0 +1,32 @@ +package com.plotsquared.core.persistence.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; + +@Entity +@Table(name = "cluster_invited") +@IdClass(ClusterUserId.class) +@NamedQueries({ + @NamedQuery(name = "ClusterInvited.delete", query = "DELETE FROM ClusterInvitedEntity e WHERE e.clusterId = :clusterId AND e.userUuid = :uuid"), + @NamedQuery(name = "ClusterInvited.findUsers", query = "SELECT e.userUuid FROM ClusterInvitedEntity e WHERE e.clusterId = :clusterId") +}) +public class ClusterInvitedEntity { + @Id + @Column(name = "cluster_id") + private Long clusterId; + @Id + @Column(name = "user_uuid", length = 40) + private String userUuid; + + public ClusterInvitedEntity() {} + + public Long getClusterId() { return clusterId; } + public void setClusterId(Long clusterId) { this.clusterId = clusterId; } + public String getUserUuid() { return userUuid; } + public void setUserUuid(String userUuid) { this.userUuid = userUuid; } +} From a9fc2bc8b071090be90a839e8c2344a6db98c9af Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 12:13:47 +0200 Subject: [PATCH 018/141] feat: add PlayerMetaEntity class for database representation of player metadata --- .../persistence/entity/PlayerMetaEntity.java | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/entity/PlayerMetaEntity.java diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlayerMetaEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlayerMetaEntity.java new file mode 100644 index 0000000000..e6039d21d9 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlayerMetaEntity.java @@ -0,0 +1,42 @@ +package com.plotsquared.core.persistence.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Lob; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; + +@Entity +@Table(name = "player_meta") +@NamedQueries({ + @NamedQuery(name = "PlayerMeta.findByUuid", query = "SELECT m FROM PlayerMetaEntity m WHERE m.uuid = :uuid"), + @NamedQuery(name = "PlayerMeta.deleteByUuidAndKey", query = "DELETE FROM PlayerMetaEntity m WHERE m.uuid = :uuid AND m.key = :key") +}) +public class PlayerMetaEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "meta_id") + private Long id; + @Column(length = 40, nullable = false) + private String uuid; + @Column(name = "key", length = 32, nullable = false) + private String key; + @Lob + @Column(name = "value", nullable = false) + private byte[] value; + + public PlayerMetaEntity() {} + + public Long getId() { return id; } + public void setId(Long id) { this.id = id; } + public String getUuid() { return uuid; } + public void setUuid(String uuid) { this.uuid = uuid; } + public String getKey() { return key; } + public void setKey(String key) { this.key = key; } + public byte[] getValue() { return value; } + public void setValue(byte[] value) { this.value = value; } +} From 6fbbf5d9e9252c6aff1d89a6b7903e37a4df8ee1 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 12:14:16 +0200 Subject: [PATCH 019/141] feat: add PlotFlagEntity class for database representation of plot flags --- .../persistence/entity/PlotFlagEntity.java | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/entity/PlotFlagEntity.java diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotFlagEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotFlagEntity.java new file mode 100644 index 0000000000..d67f9c3234 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotFlagEntity.java @@ -0,0 +1,48 @@ +package com.plotsquared.core.persistence.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; + +@Entity +@Table(name = "plot_flags", uniqueConstraints = @UniqueConstraint(columnNames = {"plot_id","flag"})) +@NamedQueries({ + @NamedQuery(name = "PlotFlag.findByPlot", query = "SELECT f FROM PlotFlagEntity f WHERE f.plot.id = :plotId"), + @NamedQuery(name = "PlotFlag.findByPlotAndName", query = "SELECT f FROM PlotFlagEntity f WHERE f.plot.id = :plotId AND f.flag = :flag"), + @NamedQuery(name = "PlotFlag.deleteByPlotAndName", query = "DELETE FROM PlotFlagEntity f WHERE f.plot.id = :plotId AND f.flag = :flag") +}) +public class PlotFlagEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "plot_id", nullable = false) + private PlotEntity plot; + @Column(length = 64) + private String flag; + @Column(length = 512) + private String value; + + public PlotFlagEntity() {} + + public Long getId() { return id; } + public void setId(Long id) { this.id = id; } + + public PlotEntity getPlot() { return plot; } + public void setPlot(PlotEntity plot) { this.plot = plot; } + + public String getFlag() { return flag; } + public void setFlag(String flag) { this.flag = flag; } + + public String getValue() { return value; } + public void setValue(String value) { this.value = value; } +} From 034607e334f8f207270da33a95ea7db63a9aa21e Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 12:50:32 +0200 Subject: [PATCH 020/141] feat: add PersistenceModule for database configuration and entity management --- .../persistence/config/PersistenceModule.java | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java b/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java new file mode 100644 index 0000000000..8dcc4d5e36 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java @@ -0,0 +1,73 @@ +package com.plotsquared.core.persistence.config; + +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import com.google.inject.Singleton; +import com.plotsquared.core.configuration.Storage; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.Persistence; +import org.flywaydb.core.Flyway; + +import java.util.HashMap; +import java.util.Map; + +public class PersistenceModule extends AbstractModule { + + @Provides + EntityManager provideEm(EntityManagerFactory emf) { + return emf.createEntityManager(); + } + + @Provides + @Singleton + EntityManagerFactory provideEmf() { + Map props = new HashMap<>(); + + if (Storage.MySQL.USE) { + String url = "jdbc:mysql://" + Storage.MySQL.HOST + ":" + Storage.MySQL.PORT + "/" + Storage.MySQL.DATABASE + + "?" + String.join("&", Storage.MySQL.PROPERTIES); + props.put("jakarta.persistence.jdbc.url", url); + props.put("jakarta.persistence.jdbc.user", Storage.MySQL.USER); + props.put("jakarta.persistence.jdbc.password", Storage.MySQL.PASSWORD); + props.put("jakarta.persistence.jdbc.driver", "com.mysql.cj.jdbc.Driver"); + props.put("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect"); + } else if (Storage.SQLite.USE) { + String url = "jdbc:sqlite:" + Storage.SQLite.DB + ".db"; + props.put("jakarta.persistence.jdbc.url", url); + props.put("jakarta.persistence.jdbc.driver", "org.sqlite.JDBC"); + props.put("hibernate.dialect", "org.hibernate.community.dialect.SQLiteDialect"); + } + + // Schema via Flyway; only validate with Hibernate + props.put("hibernate.hbm2ddl.auto", "validate"); + props.put("hibernate.show_sql", false); + props.put("hibernate.format_sql", false); + + // Apply dynamic table prefixing + props.put("hibernate.physical_naming_strategy", new PrefixedNamingStrategy(Storage.PREFIX)); + + return Persistence.createEntityManagerFactory("plotsquaredPU", props); + } + + @Provides + @Singleton + Flyway provideFlyway() { + String url; + String user = null; + String pass = null; + if (Storage.MySQL.USE) { + url = "jdbc:mysql://" + Storage.MySQL.HOST + ":" + Storage.MySQL.PORT + "/" + Storage.MySQL.DATABASE + + "?" + String.join("&", Storage.MySQL.PROPERTIES); + user = Storage.MySQL.USER; + pass = Storage.MySQL.PASSWORD; + } else { + url = "jdbc:sqlite:" + Storage.SQLite.DB + ".db"; + } + return Flyway.configure() + .dataSource(url, user, pass) + .locations("classpath:db/migration") + .baselineOnMigrate(true) + .load(); + } +} From c4f5c6e7bb091fbe02eb3d9064c9712be0a844e3 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 12:50:40 +0200 Subject: [PATCH 021/141] feat: add PrefixedNamingStrategy for custom table naming in database --- .../config/PrefixedNamingStrategy.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/config/PrefixedNamingStrategy.java diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/PrefixedNamingStrategy.java b/Core/src/main/java/com/plotsquared/core/persistence/config/PrefixedNamingStrategy.java new file mode 100644 index 0000000000..21e21db40b --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/PrefixedNamingStrategy.java @@ -0,0 +1,43 @@ +package com.plotsquared.core.persistence.config; + +import org.hibernate.boot.model.naming.Identifier; +import org.hibernate.boot.model.naming.PhysicalNamingStrategy; +import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; + +public class PrefixedNamingStrategy implements PhysicalNamingStrategy { + + private final String prefix; + + public PrefixedNamingStrategy(String prefix) { + this.prefix = prefix == null ? "" : prefix; + } + + @Override + public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment env) { + if (name == null) { + return null; + } + return Identifier.toIdentifier(prefix + name.getText(), name.isQuoted()); + } + + @Override + public Identifier toPhysicalCatalogName(Identifier n, JdbcEnvironment e) { + return n; + } + + @Override + public Identifier toPhysicalSchemaName(Identifier n, JdbcEnvironment e) { + return n; + } + + @Override + public Identifier toPhysicalSequenceName(Identifier n, JdbcEnvironment e) { + return n; + } + + @Override + public Identifier toPhysicalColumnName(Identifier n, JdbcEnvironment e) { + return n; + } + +} From ede12b4a75e3d3cbcdc246210b6b35f881ba462e Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 13:14:07 +0200 Subject: [PATCH 022/141] feat: add repository interfaces for cluster and plot management --- .../repository/api/ClusterHelperRepository.java | 9 +++++++++ .../repository/api/ClusterInvitedRepository.java | 9 +++++++++ .../repository/api/ClusterRepository.java | 14 ++++++++++++++ .../repository/api/PlayerMetaRepository.java | 11 +++++++++++ .../repository/api/PlotCommentRepository.java | 12 ++++++++++++ .../repository/api/PlotDeniedRepository.java | 9 +++++++++ .../repository/api/PlotFlagRepository.java | 13 +++++++++++++ .../repository/api/PlotMembershipRepository.java | 9 +++++++++ .../repository/api/PlotRatingRepository.java | 10 ++++++++++ .../repository/api/PlotRepository.java | 15 +++++++++++++++ .../repository/api/PlotSettingsRepository.java | 11 +++++++++++ .../repository/api/PlotTrustedRepository.java | 9 +++++++++ 12 files changed, 131 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterHelperRepository.java create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterInvitedRepository.java create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterRepository.java create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlayerMetaRepository.java create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotCommentRepository.java create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotDeniedRepository.java create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotFlagRepository.java create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotMembershipRepository.java create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRatingRepository.java create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotSettingsRepository.java create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotTrustedRepository.java diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterHelperRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterHelperRepository.java new file mode 100644 index 0000000000..9a08fe0ac0 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterHelperRepository.java @@ -0,0 +1,9 @@ +package com.plotsquared.core.persistence.repository.api; + +import java.util.List; + +public interface ClusterHelperRepository { + List findUsers(long clusterId); + void add(long clusterId, String userUuid); + void remove(long clusterId, String userUuid); +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterInvitedRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterInvitedRepository.java new file mode 100644 index 0000000000..6710eb80b9 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterInvitedRepository.java @@ -0,0 +1,9 @@ +package com.plotsquared.core.persistence.repository.api; + +import java.util.List; + +public interface ClusterInvitedRepository { + List findUsers(long clusterId); + void add(long clusterId, String userUuid); + void remove(long clusterId, String userUuid); +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterRepository.java new file mode 100644 index 0000000000..104c38d004 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterRepository.java @@ -0,0 +1,14 @@ +package com.plotsquared.core.persistence.repository.api; + +import com.plotsquared.core.persistence.entity.ClusterEntity; + +import java.util.List; +import java.util.Optional; + +public interface ClusterRepository { + Optional findById(long id); + Optional findByWorldAndBounds(String world, int x, int z); + List findByWorld(String world); + void save(ClusterEntity cluster); + void deleteById(long id); +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlayerMetaRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlayerMetaRepository.java new file mode 100644 index 0000000000..15ce9b25b7 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlayerMetaRepository.java @@ -0,0 +1,11 @@ +package com.plotsquared.core.persistence.repository.api; + +import com.plotsquared.core.persistence.entity.PlayerMetaEntity; + +import java.util.List; + +public interface PlayerMetaRepository { + List findByUuid(String uuid); + void put(String uuid, String key, byte[] value); + void delete(String uuid, String key); +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotCommentRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotCommentRepository.java new file mode 100644 index 0000000000..361f26c6da --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotCommentRepository.java @@ -0,0 +1,12 @@ +package com.plotsquared.core.persistence.repository.api; + +import com.plotsquared.core.persistence.entity.PlotCommentEntity; + +import java.util.List; + +public interface PlotCommentRepository { + List findByWorldAndInbox(String world, String inbox); + void save(PlotCommentEntity entity); + void deleteOne(String world, int hashcode, String inbox, String sender); + void clearInbox(String world, String inbox); +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotDeniedRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotDeniedRepository.java new file mode 100644 index 0000000000..ac2248539f --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotDeniedRepository.java @@ -0,0 +1,9 @@ +package com.plotsquared.core.persistence.repository.api; + +import java.util.List; + +public interface PlotDeniedRepository { + List findUsers(long plotId); + void add(long plotId, String userUuid); + void remove(long plotId, String userUuid); +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotFlagRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotFlagRepository.java new file mode 100644 index 0000000000..f7c8f7032c --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotFlagRepository.java @@ -0,0 +1,13 @@ +package com.plotsquared.core.persistence.repository.api; + +import com.plotsquared.core.persistence.entity.PlotFlagEntity; + +import java.util.List; +import java.util.Optional; + +public interface PlotFlagRepository { + List findByPlotId(long plotId); + Optional findByPlotAndName(long plotId, String flagName); + void save(PlotFlagEntity entity); + void deleteByPlotAndName(long plotId, String flagName); +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotMembershipRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotMembershipRepository.java new file mode 100644 index 0000000000..f4dca3b896 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotMembershipRepository.java @@ -0,0 +1,9 @@ +package com.plotsquared.core.persistence.repository.api; + +import java.util.List; + +public interface PlotMembershipRepository { + List findUsers(long plotId); + void add(long plotId, String userUuid); + void remove(long plotId, String userUuid); +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRatingRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRatingRepository.java new file mode 100644 index 0000000000..161cb68089 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRatingRepository.java @@ -0,0 +1,10 @@ +package com.plotsquared.core.persistence.repository.api; + +import com.plotsquared.core.persistence.entity.PlotRatingEntity; + +import java.util.List; + +public interface PlotRatingRepository { + List findByPlotId(long plotId); + void upsert(long plotId, String playerUuid, int rating); +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java new file mode 100644 index 0000000000..012c2ba887 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java @@ -0,0 +1,15 @@ +package com.plotsquared.core.persistence.repository.api; + +import com.plotsquared.core.persistence.entity.PlotEntity; + +import java.util.List; +import java.util.Optional; + +public interface PlotRepository { + Optional findById(long id); + Optional findByWorldAndId(String world, int x, int z); + List findByOwner(String ownerUuid); + List findByWorld(String world); + void save(PlotEntity plot); + void deleteById(long id); +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotSettingsRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotSettingsRepository.java new file mode 100644 index 0000000000..eb845e6b31 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotSettingsRepository.java @@ -0,0 +1,11 @@ +package com.plotsquared.core.persistence.repository.api; + +import com.plotsquared.core.persistence.entity.PlotSettingsEntity; + +import java.util.Optional; + +public interface PlotSettingsRepository { + Optional findByPlotId(long plotId); + void save(PlotSettingsEntity settings); + void deleteByPlotId(long plotId); +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotTrustedRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotTrustedRepository.java new file mode 100644 index 0000000000..ec1d34afa2 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotTrustedRepository.java @@ -0,0 +1,9 @@ +package com.plotsquared.core.persistence.repository.api; + +import java.util.List; + +public interface PlotTrustedRepository { + List findUsers(long plotId); + void add(long plotId, String userUuid); + void remove(long plotId, String userUuid); +} From cba4edf54853e28eb86c2edcd6e31a19b668c58b Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 13:23:26 +0200 Subject: [PATCH 023/141] feat: implement JPA repositories for cluster and plot management --- .../jpa/ClusterHelperRepositoryJpa.java | 76 ++++++++++++ .../jpa/ClusterInvitedRepositoryJpa.java | 76 ++++++++++++ .../repository/jpa/ClusterRepositoryJpa.java | 92 ++++++++++++++ .../jpa/PlayerMetaRepositoryJpa.java | 82 +++++++++++++ .../jpa/PlotCommentRepositoryJpa.java | 96 +++++++++++++++ .../jpa/PlotDeniedRepositoryJpa.java | 70 +++++++++++ .../repository/jpa/PlotFlagRepositoryJpa.java | 98 +++++++++++++++ .../jpa/PlotMembershipRepositoryJpa.java | 70 +++++++++++ .../jpa/PlotRatingRepositoryJpa.java | 64 ++++++++++ .../repository/jpa/PlotRepositoryJpa.java | 114 ++++++++++++++++++ .../jpa/PlotSettingsRepositoryJpa.java | 75 ++++++++++++ .../jpa/PlotTrustedRepositoryJpa.java | 70 +++++++++++ 12 files changed, 983 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterHelperRepositoryJpa.java create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterInvitedRepositoryJpa.java create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterRepositoryJpa.java create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlayerMetaRepositoryJpa.java create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotCommentRepositoryJpa.java create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotDeniedRepositoryJpa.java create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotFlagRepositoryJpa.java create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotMembershipRepositoryJpa.java create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRatingRepositoryJpa.java create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotSettingsRepositoryJpa.java create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotTrustedRepositoryJpa.java diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterHelperRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterHelperRepositoryJpa.java new file mode 100644 index 0000000000..04a4c9f207 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterHelperRepositoryJpa.java @@ -0,0 +1,76 @@ +package com.plotsquared.core.persistence.repository.jpa; + +import com.google.inject.Inject; +import com.plotsquared.core.persistence.entity.ClusterHelperEntity; +import com.plotsquared.core.persistence.repository.api.ClusterHelperRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.List; + +public class ClusterHelperRepositoryJpa implements ClusterHelperRepository { + + private static final Logger LOGGER = LogManager.getLogger(ClusterHelperRepositoryJpa.class); + + private final EntityManagerFactory emf; + + @Inject + public ClusterHelperRepositoryJpa(EntityManagerFactory emf) { + this.emf = emf; + } + + @Override + public List findUsers(long clusterId) { + EntityManager em = emf.createEntityManager(); + try { + return em.createNamedQuery("ClusterHelper.findUsers", String.class) + .setParameter("clusterId", clusterId) + .getResultList(); + } finally { + em.close(); + } + } + + @Override + public void add(long clusterId, String userUuid) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + ClusterHelperEntity e = new ClusterHelperEntity(); + e.setClusterId(clusterId); + e.setUserUuid(userUuid); + em.persist(e); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to add cluster helper (clusterId={}, userUuid={})", clusterId, userUuid, ex); + throw ex; + } finally { + em.close(); + } + } + + @Override + public void remove(long clusterId, String userUuid) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + em.createNamedQuery("ClusterHelper.delete") + .setParameter("clusterId", clusterId) + .setParameter("uuid", userUuid) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to remove cluster helper (clusterId={}, userUuid={})", clusterId, userUuid, ex); + throw ex; + } finally { + em.close(); + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterInvitedRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterInvitedRepositoryJpa.java new file mode 100644 index 0000000000..d4cca771ed --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterInvitedRepositoryJpa.java @@ -0,0 +1,76 @@ +package com.plotsquared.core.persistence.repository.jpa; + +import com.google.inject.Inject; +import com.plotsquared.core.persistence.entity.ClusterInvitedEntity; +import com.plotsquared.core.persistence.repository.api.ClusterInvitedRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.List; + +public class ClusterInvitedRepositoryJpa implements ClusterInvitedRepository { + + private static final Logger LOGGER = LogManager.getLogger(ClusterInvitedRepositoryJpa.class); + + private final EntityManagerFactory emf; + + @Inject + public ClusterInvitedRepositoryJpa(EntityManagerFactory emf) { + this.emf = emf; + } + + @Override + public List findUsers(long clusterId) { + EntityManager em = emf.createEntityManager(); + try { + return em.createNamedQuery("ClusterInvited.findUsers", String.class) + .setParameter("clusterId", clusterId) + .getResultList(); + } finally { + em.close(); + } + } + + @Override + public void add(long clusterId, String userUuid) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + ClusterInvitedEntity e = new ClusterInvitedEntity(); + e.setClusterId(clusterId); + e.setUserUuid(userUuid); + em.persist(e); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to add cluster invited (clusterId={}, userUuid={})", clusterId, userUuid, ex); + throw ex; + } finally { + em.close(); + } + } + + @Override + public void remove(long clusterId, String userUuid) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + em.createNamedQuery("ClusterInvited.delete") + .setParameter("clusterId", clusterId) + .setParameter("uuid", userUuid) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to remove cluster invited (clusterId={}, userUuid={})", clusterId, userUuid, ex); + throw ex; + } finally { + em.close(); + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterRepositoryJpa.java new file mode 100644 index 0000000000..94b2c189c1 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterRepositoryJpa.java @@ -0,0 +1,92 @@ +package com.plotsquared.core.persistence.repository.jpa; + +import com.google.inject.Inject; +import com.plotsquared.core.persistence.entity.ClusterEntity; +import com.plotsquared.core.persistence.repository.api.ClusterRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.List; +import java.util.Optional; + +public class ClusterRepositoryJpa implements ClusterRepository { + + private static final Logger LOGGER = LogManager.getLogger(ClusterRepositoryJpa.class); + + private final EntityManagerFactory emf; + + @Inject + public ClusterRepositoryJpa(EntityManagerFactory emf) { + this.emf = emf; + } + + @Override + public Optional findById(long id) { + EntityManager em = emf.createEntityManager(); + try { + return Optional.ofNullable(em.find(ClusterEntity.class, id)); + } finally { em.close(); } + } + + @Override + public Optional findByWorldAndBounds(String world, int x, int z) { + EntityManager em = emf.createEntityManager(); + try { + return em.createNamedQuery("Cluster.findByWorldAndBounds", ClusterEntity.class) + .setParameter("world", world) + .setParameter("x", x) + .setParameter("z", z) + .getResultStream().findFirst(); + } finally { em.close(); } + } + + @Override + public List findByWorld(String world) { + EntityManager em = emf.createEntityManager(); + try { + return em.createQuery("SELECT c FROM ClusterEntity c WHERE c.world = :world", ClusterEntity.class) + .setParameter("world", world) + .getResultList(); + } finally { em.close(); } + } + + @Override + public void save(ClusterEntity cluster) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + if (cluster.getId() == null) { + em.persist(cluster); + } else { + em.merge(cluster); + } + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to save cluster (id={}, world={})", cluster.getId(), cluster.getWorld(), ex); + throw ex; + } finally { em.close(); } + } + + @Override + public void deleteById(long id) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + ClusterEntity e = em.find(ClusterEntity.class, id); + if (e != null) { + em.remove(e); + } + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to delete cluster by id (id={})", id, ex); + throw ex; + } finally { em.close(); } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlayerMetaRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlayerMetaRepositoryJpa.java new file mode 100644 index 0000000000..7afb123008 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlayerMetaRepositoryJpa.java @@ -0,0 +1,82 @@ +package com.plotsquared.core.persistence.repository.jpa; + +import com.google.inject.Inject; +import com.plotsquared.core.persistence.entity.PlayerMetaEntity; +import com.plotsquared.core.persistence.repository.api.PlayerMetaRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.List; + +public class PlayerMetaRepositoryJpa implements PlayerMetaRepository { + + private static final Logger LOGGER = LogManager.getLogger(PlayerMetaRepositoryJpa.class); + + private final EntityManagerFactory emf; + + @Inject + public PlayerMetaRepositoryJpa(EntityManagerFactory emf) { + this.emf = emf; + } + + @Override + public List findByUuid(String uuid) { + EntityManager em = emf.createEntityManager(); + try { + return em.createNamedQuery("PlayerMeta.findByUuid", PlayerMetaEntity.class) + .setParameter("uuid", uuid) + .getResultList(); + } finally { + em.close(); + } + } + + @Override + public void put(String uuid, String key, byte[] value) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + // Delete existing row for same (uuid,key) then insert new + em.createNamedQuery("PlayerMeta.deleteByUuidAndKey") + .setParameter("uuid", uuid) + .setParameter("key", key) + .executeUpdate(); + PlayerMetaEntity e = new PlayerMetaEntity(); + e.setUuid(uuid); + e.setKey(key); + e.setValue(value); + em.persist(e); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to put player meta (uuid={}, key={}, value.length={})", uuid, key, value != null ? value.length : null, ex); + throw ex; + } finally { + em.close(); + } + } + + @Override + public void delete(String uuid, String key) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + em.createNamedQuery("PlayerMeta.deleteByUuidAndKey") + .setParameter("uuid", uuid) + .setParameter("key", key) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to delete player meta (uuid={}, key={})", uuid, key, ex); + throw ex; + } finally { + em.close(); + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotCommentRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotCommentRepositoryJpa.java new file mode 100644 index 0000000000..d84e994d78 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotCommentRepositoryJpa.java @@ -0,0 +1,96 @@ +package com.plotsquared.core.persistence.repository.jpa; + +import com.google.inject.Inject; +import com.plotsquared.core.persistence.entity.PlotCommentEntity; +import com.plotsquared.core.persistence.repository.api.PlotCommentRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.List; + +public class PlotCommentRepositoryJpa implements PlotCommentRepository { + + private static final Logger LOGGER = LogManager.getLogger(PlotCommentRepositoryJpa.class); + + private final EntityManagerFactory emf; + + @Inject + public PlotCommentRepositoryJpa(EntityManagerFactory emf) { + this.emf = emf; + } + + @Override + public List findByWorldAndInbox(String world, String inbox) { + EntityManager em = emf.createEntityManager(); + try { + return em.createNamedQuery("PlotComment.findByWorldAndInbox", PlotCommentEntity.class) + .setParameter("world", world) + .setParameter("inbox", inbox) + .getResultList(); + } finally { + em.close(); + } + } + + @Override + public void save(PlotCommentEntity entity) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + em.persist(entity); + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to save plot comment (world={}, inbox={}, hashcode={})", entity.getWorld(), entity.getInbox(), entity.getHashcode(), e); + throw e; + } finally { + em.close(); + } + } + + @Override + public void deleteOne(String world, int hashcode, String inbox, String sender) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + em.createNamedQuery("PlotComment.deleteOne") + .setParameter("world", world) + .setParameter("hash", hashcode) + .setParameter("inbox", inbox) + .setParameter("sender", sender) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to delete one plot comment (world={}, inbox={}, hashcode={}, sender={})", world, inbox, hashcode, sender, e); + throw e; + } finally { + em.close(); + } + } + + @Override + public void clearInbox(String world, String inbox) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + em.createNamedQuery("PlotComment.clearInbox") + .setParameter("world", world) + .setParameter("inbox", inbox) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to clear inbox (world={}, inbox={})", world, inbox, e); + throw e; + } finally { + em.close(); + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotDeniedRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotDeniedRepositoryJpa.java new file mode 100644 index 0000000000..20c6d1a844 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotDeniedRepositoryJpa.java @@ -0,0 +1,70 @@ +package com.plotsquared.core.persistence.repository.jpa; + +import com.google.inject.Inject; +import com.plotsquared.core.persistence.entity.PlotDeniedEntity; +import com.plotsquared.core.persistence.repository.api.PlotDeniedRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.List; + +public class PlotDeniedRepositoryJpa implements PlotDeniedRepository { + + private static final Logger LOGGER = LogManager.getLogger(PlotDeniedRepositoryJpa.class); + + private final EntityManagerFactory emf; + + @Inject + public PlotDeniedRepositoryJpa(EntityManagerFactory emf) { + this.emf = emf; + } + + @Override + public List findUsers(long plotId) { + EntityManager em = emf.createEntityManager(); + try { + return em.createNamedQuery("PlotDenied.findUsers", String.class) + .setParameter("plotId", plotId) + .getResultList(); + } finally { em.close(); } + } + + @Override + public void add(long plotId, String userUuid) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + PlotDeniedEntity e = new PlotDeniedEntity(); + e.setPlotId(plotId); + e.setUserUuid(userUuid); + em.persist(e); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to add plot denied (plotId={}, userUuid={})", plotId, userUuid, ex); + throw ex; + } finally { em.close(); } + } + + @Override + public void remove(long plotId, String userUuid) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + em.createNamedQuery("PlotDenied.delete") + .setParameter("plotId", plotId) + .setParameter("uuid", userUuid) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to remove plot denied (plotId={}, userUuid={})", plotId, userUuid, ex); + throw ex; + } finally { em.close(); } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotFlagRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotFlagRepositoryJpa.java new file mode 100644 index 0000000000..70717a191a --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotFlagRepositoryJpa.java @@ -0,0 +1,98 @@ +package com.plotsquared.core.persistence.repository.jpa; + +import com.google.inject.Inject; +import com.plotsquared.core.persistence.entity.PlotEntity; +import com.plotsquared.core.persistence.entity.PlotFlagEntity; +import com.plotsquared.core.persistence.repository.api.PlotFlagRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.List; +import java.util.Optional; + +public class PlotFlagRepositoryJpa implements PlotFlagRepository { + + private static final Logger LOGGER = LogManager.getLogger(PlotFlagRepositoryJpa.class); + + private final EntityManagerFactory emf; + + @Inject + public PlotFlagRepositoryJpa(EntityManagerFactory emf) { + this.emf = emf; + } + + @Override + public List findByPlotId(long plotId) { + EntityManager em = emf.createEntityManager(); + try { + return em.createNamedQuery("PlotFlag.findByPlot", PlotFlagEntity.class) + .setParameter("plotId", plotId) + .getResultList(); + } finally { + em.close(); + } + } + + @Override + public Optional findByPlotAndName(long plotId, String flagName) { + EntityManager em = emf.createEntityManager(); + try { + return em.createNamedQuery("PlotFlag.findByPlotAndName", PlotFlagEntity.class) + .setParameter("plotId", plotId) + .setParameter("flag", flagName) + .getResultStream().findFirst(); + } finally { + em.close(); + } + } + + @Override + public void save(PlotFlagEntity entity) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + if (entity.getId() == null) { + // ensure Plot reference is managed if set by id only + PlotEntity plot = entity.getPlot(); + if (plot != null && plot.getId() != null && !em.contains(plot)) { + plot = em.getReference(PlotEntity.class, plot.getId()); + entity.setPlot(plot); + } + em.persist(entity); + } else { + em.merge(entity); + } + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to save plot flag (plotId={}, flag={})", entity.getPlot() != null ? entity.getPlot().getId() : null, entity.getFlag(), e); + throw e; + } finally { + em.close(); + } + } + + @Override + public void deleteByPlotAndName(long plotId, String flagName) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + em.createNamedQuery("PlotFlag.deleteByPlotAndName") + .setParameter("plotId", plotId) + .setParameter("flag", flagName) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to delete plot flag (plotId={}, flag={})", plotId, flagName, e); + throw e; + } finally { + em.close(); + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotMembershipRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotMembershipRepositoryJpa.java new file mode 100644 index 0000000000..696ff7cc98 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotMembershipRepositoryJpa.java @@ -0,0 +1,70 @@ +package com.plotsquared.core.persistence.repository.jpa; + +import com.google.inject.Inject; +import com.plotsquared.core.persistence.entity.PlotMembershipEntity; +import com.plotsquared.core.persistence.repository.api.PlotMembershipRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.List; + +public class PlotMembershipRepositoryJpa implements PlotMembershipRepository { + + private static final Logger LOGGER = LogManager.getLogger(PlotMembershipRepositoryJpa.class); + + private final EntityManagerFactory emf; + + @Inject + public PlotMembershipRepositoryJpa(EntityManagerFactory emf) { + this.emf = emf; + } + + @Override + public List findUsers(long plotId) { + EntityManager em = emf.createEntityManager(); + try { + return em.createNamedQuery("PlotHelper.findUsers", String.class) + .setParameter("plotId", plotId) + .getResultList(); + } finally { em.close(); } + } + + @Override + public void add(long plotId, String userUuid) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + PlotMembershipEntity e = new PlotMembershipEntity(); + e.setPlotId(plotId); + e.setUserUuid(userUuid); + em.persist(e); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to add plot member (plotId={}, userUuid={})", plotId, userUuid, ex); + throw ex; + } finally { em.close(); } + } + + @Override + public void remove(long plotId, String userUuid) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + em.createNamedQuery("PlotHelper.delete") + .setParameter("plotId", plotId) + .setParameter("uuid", userUuid) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to remove plot member (plotId={}, userUuid={})", plotId, userUuid, ex); + throw ex; + } finally { em.close(); } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRatingRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRatingRepositoryJpa.java new file mode 100644 index 0000000000..796480e273 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRatingRepositoryJpa.java @@ -0,0 +1,64 @@ +package com.plotsquared.core.persistence.repository.jpa; + +import com.google.inject.Inject; +import com.plotsquared.core.persistence.entity.PlotRatingEntity; +import com.plotsquared.core.persistence.repository.api.PlotRatingRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.List; + +public class PlotRatingRepositoryJpa implements PlotRatingRepository { + + private static final Logger LOGGER = LogManager.getLogger(PlotRatingRepositoryJpa.class); + + private final EntityManagerFactory emf; + + @Inject + public PlotRatingRepositoryJpa(EntityManagerFactory emf) { + this.emf = emf; + } + + @Override + public List findByPlotId(long plotId) { + EntityManager em = emf.createEntityManager(); + try { + return em.createNamedQuery("PlotRating.findByPlot", PlotRatingEntity.class) + .setParameter("plotId", plotId) + .getResultList(); + } finally { + em.close(); + } + } + + @Override + public void upsert(long plotId, String playerUuid, int rating) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + int updated = em.createNamedQuery("PlotRating.updateValue") + .setParameter("rating", rating) + .setParameter("plotId", plotId) + .setParameter("player", playerUuid) + .executeUpdate(); + if (updated == 0) { + PlotRatingEntity entity = new PlotRatingEntity(); + entity.setPlotId(plotId); + entity.setPlayer(playerUuid); + entity.setRating(rating); + em.persist(entity); + } + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to upsert plot rating (plotId={}, playerUuid={}, rating={})", plotId, playerUuid, rating, e); + throw e; + } finally { + em.close(); + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java new file mode 100644 index 0000000000..5edcab1bc0 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java @@ -0,0 +1,114 @@ +package com.plotsquared.core.persistence.repository.jpa; + +import com.google.inject.Inject; +import com.plotsquared.core.persistence.entity.PlotEntity; +import com.plotsquared.core.persistence.repository.api.PlotRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.List; +import java.util.Optional; + +public class PlotRepositoryJpa implements PlotRepository { + + private static final Logger LOGGER = LogManager.getLogger(PlotRepositoryJpa.class); + + private final EntityManagerFactory emf; + + @Inject + public PlotRepositoryJpa(EntityManagerFactory emf) { + this.emf = emf; + } + + @Override + public Optional findById(long id) { + EntityManager em = emf.createEntityManager(); + try { + return Optional.ofNullable(em.find(PlotEntity.class, id)); + } finally { + em.close(); + } + } + + @Override + public Optional findByWorldAndId(String world, int x, int z) { + EntityManager em = emf.createEntityManager(); + try { + return em.createNamedQuery("Plot.findByWorldAndId", PlotEntity.class) + .setParameter("world", world) + .setParameter("x", x) + .setParameter("z", z) + .getResultStream().findFirst(); + } finally { + em.close(); + } + } + + @Override + public List findByOwner(String ownerUuid) { + EntityManager em = emf.createEntityManager(); + try { + return em.createNamedQuery("Plot.findByOwner", PlotEntity.class) + .setParameter("owner", ownerUuid) + .getResultList(); + } finally { + em.close(); + } + } + + @Override + public List findByWorld(String world) { + EntityManager em = emf.createEntityManager(); + try { + return em.createNamedQuery("Plot.findByWorld", PlotEntity.class) + .setParameter("world", world) + .getResultList(); + } finally { + em.close(); + } + } + + @Override + public void save(PlotEntity plot) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + if (plot.getId() == null) { + em.persist(plot); + } else { + em.merge(plot); + } + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to save plot (id={}, world={}, x={}, z={})", plot.getId(), plot.getWorld(), plot.getPlotIdX(), plot.getPlotIdZ(), e); + throw e; + } finally { + em.close(); + } + } + + @Override + public void deleteById(long id) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + PlotEntity ref = em.find(PlotEntity.class, id); + if (ref != null) { + em.remove(ref); + } + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to delete plot by id (id={})", id, e); + throw e; + } finally { + em.close(); + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotSettingsRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotSettingsRepositoryJpa.java new file mode 100644 index 0000000000..67f6b54982 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotSettingsRepositoryJpa.java @@ -0,0 +1,75 @@ +package com.plotsquared.core.persistence.repository.jpa; + +import com.google.inject.Inject; +import com.plotsquared.core.persistence.entity.PlotSettingsEntity; +import com.plotsquared.core.persistence.repository.api.PlotSettingsRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.Optional; + +public class PlotSettingsRepositoryJpa implements PlotSettingsRepository { + + private static final Logger LOGGER = LogManager.getLogger(PlotSettingsRepositoryJpa.class); + + private final EntityManagerFactory emf; + + @Inject + public PlotSettingsRepositoryJpa(EntityManagerFactory emf) { + this.emf = emf; + } + + @Override + public Optional findByPlotId(long plotId) { + EntityManager em = emf.createEntityManager(); + try { + return Optional.ofNullable(em.find(PlotSettingsEntity.class, plotId)); + } finally { + em.close(); + } + } + + @Override + public void save(PlotSettingsEntity settings) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + if (settings.getId() == null) { + em.persist(settings); + } else { + em.merge(settings); + } + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to save plot settings (plotId={})", settings.getId(), e); + throw e; + } finally { + em.close(); + } + } + + @Override + public void deleteByPlotId(long plotId) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + PlotSettingsEntity e = em.find(PlotSettingsEntity.class, plotId); + if (e != null) { + em.remove(e); + } + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to delete plot settings (plotId={})", plotId, ex); + throw ex; + } finally { + em.close(); + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotTrustedRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotTrustedRepositoryJpa.java new file mode 100644 index 0000000000..f2491b2660 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotTrustedRepositoryJpa.java @@ -0,0 +1,70 @@ +package com.plotsquared.core.persistence.repository.jpa; + +import com.google.inject.Inject; +import com.plotsquared.core.persistence.entity.PlotTrustedEntity; +import com.plotsquared.core.persistence.repository.api.PlotTrustedRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.List; + +public class PlotTrustedRepositoryJpa implements PlotTrustedRepository { + + private static final Logger LOGGER = LogManager.getLogger(PlotTrustedRepositoryJpa.class); + + private final EntityManagerFactory emf; + + @Inject + public PlotTrustedRepositoryJpa(EntityManagerFactory emf) { + this.emf = emf; + } + + @Override + public List findUsers(long plotId) { + EntityManager em = emf.createEntityManager(); + try { + return em.createNamedQuery("PlotTrusted.findUsers", String.class) + .setParameter("plotId", plotId) + .getResultList(); + } finally { em.close(); } + } + + @Override + public void add(long plotId, String userUuid) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + PlotTrustedEntity e = new PlotTrustedEntity(); + e.setPlotId(plotId); + e.setUserUuid(userUuid); + em.persist(e); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to add plot trusted (plotId={}, userUuid={})", plotId, userUuid, ex); + throw ex; + } finally { em.close(); } + } + + @Override + public void remove(long plotId, String userUuid) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + em.createNamedQuery("PlotTrusted.delete") + .setParameter("plotId", plotId) + .setParameter("uuid", userUuid) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to remove plot trusted (plotId={}, userUuid={})", plotId, userUuid, ex); + throw ex; + } finally { em.close(); } + } +} From f4145c219f72119a48cf187f89fd1478a1353bd8 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 13:29:20 +0200 Subject: [PATCH 024/141] feat: add FlywayBootstrap for automatic database migration on startup --- .../persistence/config/FlywayBootstrap.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/config/FlywayBootstrap.java diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/FlywayBootstrap.java b/Core/src/main/java/com/plotsquared/core/persistence/config/FlywayBootstrap.java new file mode 100644 index 0000000000..1d8654af94 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/FlywayBootstrap.java @@ -0,0 +1,26 @@ +package com.plotsquared.core.persistence.config; + +import com.google.inject.Inject; +import com.google.inject.Singleton; +import org.flywaydb.core.Flyway; + +import java.util.logging.Logger; + +/** + * Eager bootstrap that executes Flyway migrations during application startup. + */ +@Singleton +public class FlywayBootstrap { + private static final Logger LOGGER = Logger.getLogger(FlywayBootstrap.class.getName()); + + @Inject + public FlywayBootstrap(Flyway flyway) { + try { + flyway.migrate(); + LOGGER.info("Flyway migration complete."); + } catch (Exception e) { + LOGGER.severe("Flyway migration failed: " + e.getMessage()); + throw e; + } + } +} From 74888d0162fe702c85f2207e76e2290a76a00d61 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 13:29:33 +0200 Subject: [PATCH 025/141] feat: add JpaPropertiesProvider for dynamic JPA property configuration --- .../config/JpaPropertiesProvider.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java b/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java new file mode 100644 index 0000000000..549041e0e0 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java @@ -0,0 +1,46 @@ +package com.plotsquared.core.persistence.config; + +import com.google.inject.Singleton; +import com.plotsquared.core.configuration.Storage; + +import java.util.HashMap; +import java.util.Map; + +/** + * Builds JPA/Hibernate properties based on Storage configuration. + */ +@Singleton +public class JpaPropertiesProvider { + + /** + * Create a map of JPA properties suitable for EntityManagerFactory creation. + */ + public Map getProperties() { + Map props = new HashMap<>(); + + if (Storage.MySQL.USE) { + String url = "jdbc:mysql://" + Storage.MySQL.HOST + ":" + Storage.MySQL.PORT + "/" + Storage.MySQL.DATABASE + + "?" + String.join("&", Storage.MySQL.PROPERTIES); + props.put("jakarta.persistence.jdbc.url", url); + props.put("jakarta.persistence.jdbc.user", Storage.MySQL.USER); + props.put("jakarta.persistence.jdbc.password", Storage.MySQL.PASSWORD); + props.put("jakarta.persistence.jdbc.driver", "com.mysql.cj.jdbc.Driver"); + props.put("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect"); + } else if (Storage.SQLite.USE) { + String url = "jdbc:sqlite:" + Storage.SQLite.DB + ".db"; + props.put("jakarta.persistence.jdbc.url", url); + props.put("jakarta.persistence.jdbc.driver", "org.sqlite.JDBC"); + props.put("hibernate.dialect", "org.hibernate.community.dialect.SQLiteDialect"); + } + + // Schema is managed by Flyway; only validate with Hibernate + props.put("hibernate.hbm2ddl.auto", "validate"); + props.put("hibernate.show_sql", false); + props.put("hibernate.format_sql", false); + + // Apply dynamic table prefixing + props.put("hibernate.physical_naming_strategy", new PrefixedNamingStrategy(Storage.PREFIX)); + + return props; + } +} From a58f7ac1fa6153d652852d4b1181c08d77556b3f Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 13:29:47 +0200 Subject: [PATCH 026/141] feat: bind JPA repository interfaces to implementations and configure Flyway migrations --- .../persistence/config/PersistenceModule.java | 73 ++++++++++++------- 1 file changed, 46 insertions(+), 27 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java b/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java index 8dcc4d5e36..249c5810c5 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java @@ -4,16 +4,59 @@ import com.google.inject.Provides; import com.google.inject.Singleton; import com.plotsquared.core.configuration.Storage; +import com.plotsquared.core.persistence.repository.api.ClusterHelperRepository; +import com.plotsquared.core.persistence.repository.api.ClusterInvitedRepository; +import com.plotsquared.core.persistence.repository.api.ClusterRepository; +import com.plotsquared.core.persistence.repository.api.PlayerMetaRepository; +import com.plotsquared.core.persistence.repository.api.PlotCommentRepository; +import com.plotsquared.core.persistence.repository.api.PlotDeniedRepository; +import com.plotsquared.core.persistence.repository.api.PlotFlagRepository; +import com.plotsquared.core.persistence.repository.api.PlotMembershipRepository; +import com.plotsquared.core.persistence.repository.api.PlotRepository; +import com.plotsquared.core.persistence.repository.api.PlotSettingsRepository; +import com.plotsquared.core.persistence.repository.api.PlotTrustedRepository; +import com.plotsquared.core.persistence.repository.api.PlotRatingRepository; +import com.plotsquared.core.persistence.repository.jpa.ClusterHelperRepositoryJpa; +import com.plotsquared.core.persistence.repository.jpa.ClusterInvitedRepositoryJpa; +import com.plotsquared.core.persistence.repository.jpa.ClusterRepositoryJpa; +import com.plotsquared.core.persistence.repository.jpa.PlayerMetaRepositoryJpa; +import com.plotsquared.core.persistence.repository.jpa.PlotCommentRepositoryJpa; +import com.plotsquared.core.persistence.repository.jpa.PlotDeniedRepositoryJpa; +import com.plotsquared.core.persistence.repository.jpa.PlotFlagRepositoryJpa; +import com.plotsquared.core.persistence.repository.jpa.PlotMembershipRepositoryJpa; +import com.plotsquared.core.persistence.repository.jpa.PlotRepositoryJpa; +import com.plotsquared.core.persistence.repository.jpa.PlotSettingsRepositoryJpa; +import com.plotsquared.core.persistence.repository.jpa.PlotTrustedRepositoryJpa; +import com.plotsquared.core.persistence.repository.jpa.PlotRatingRepositoryJpa; import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManagerFactory; import jakarta.persistence.Persistence; import org.flywaydb.core.Flyway; -import java.util.HashMap; import java.util.Map; public class PersistenceModule extends AbstractModule { + @Override + protected void configure() { + // Bind repository interfaces to JPA implementations + bind(PlotRepository.class).to(PlotRepositoryJpa.class); + bind(PlotFlagRepository.class).to(PlotFlagRepositoryJpa.class); + bind(PlotCommentRepository.class).to(PlotCommentRepositoryJpa.class); + bind(PlotRatingRepository.class).to(PlotRatingRepositoryJpa.class); + bind(PlayerMetaRepository.class).to(PlayerMetaRepositoryJpa.class); + bind(PlotSettingsRepository.class).to(PlotSettingsRepositoryJpa.class); + bind(PlotMembershipRepository.class).to(PlotMembershipRepositoryJpa.class); + bind(PlotTrustedRepository.class).to(PlotTrustedRepositoryJpa.class); + bind(PlotDeniedRepository.class).to(PlotDeniedRepositoryJpa.class); + bind(ClusterRepository.class).to(ClusterRepositoryJpa.class); + bind(ClusterHelperRepository.class).to(ClusterHelperRepositoryJpa.class); + bind(ClusterInvitedRepository.class).to(ClusterInvitedRepositoryJpa.class); + + // Eagerly run Flyway migrations on startup + bind(FlywayBootstrap.class).asEagerSingleton(); + } + @Provides EntityManager provideEm(EntityManagerFactory emf) { return emf.createEntityManager(); @@ -21,32 +64,8 @@ EntityManager provideEm(EntityManagerFactory emf) { @Provides @Singleton - EntityManagerFactory provideEmf() { - Map props = new HashMap<>(); - - if (Storage.MySQL.USE) { - String url = "jdbc:mysql://" + Storage.MySQL.HOST + ":" + Storage.MySQL.PORT + "/" + Storage.MySQL.DATABASE - + "?" + String.join("&", Storage.MySQL.PROPERTIES); - props.put("jakarta.persistence.jdbc.url", url); - props.put("jakarta.persistence.jdbc.user", Storage.MySQL.USER); - props.put("jakarta.persistence.jdbc.password", Storage.MySQL.PASSWORD); - props.put("jakarta.persistence.jdbc.driver", "com.mysql.cj.jdbc.Driver"); - props.put("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect"); - } else if (Storage.SQLite.USE) { - String url = "jdbc:sqlite:" + Storage.SQLite.DB + ".db"; - props.put("jakarta.persistence.jdbc.url", url); - props.put("jakarta.persistence.jdbc.driver", "org.sqlite.JDBC"); - props.put("hibernate.dialect", "org.hibernate.community.dialect.SQLiteDialect"); - } - - // Schema via Flyway; only validate with Hibernate - props.put("hibernate.hbm2ddl.auto", "validate"); - props.put("hibernate.show_sql", false); - props.put("hibernate.format_sql", false); - - // Apply dynamic table prefixing - props.put("hibernate.physical_naming_strategy", new PrefixedNamingStrategy(Storage.PREFIX)); - + EntityManagerFactory provideEmf(JpaPropertiesProvider jpaPropertiesProvider) { + Map props = jpaPropertiesProvider.getProperties(); return Persistence.createEntityManagerFactory("plotsquaredPU", props); } From 5e1b56d918af2b2ef507d31a33d120059b4a58af Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 16:07:11 +0200 Subject: [PATCH 027/141] feat: integrate PersistenceModule into BukkitPlatform and clean up database setup code --- .../plotsquared/bukkit/BukkitPlatform.java | 23 +++---------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java index d60bbe3879..e0dbb081ed 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java @@ -85,6 +85,7 @@ import com.plotsquared.core.inject.modules.PlotSquaredModule; import com.plotsquared.core.listener.PlotListener; import com.plotsquared.core.listener.WESubscriber; +import com.plotsquared.core.persistence.config.PersistenceModule; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; @@ -298,7 +299,8 @@ public void onEnable() { new WorldManagerModule(), new PlotSquaredModule(), new BukkitModule(this), - new BackupModule() + new BackupModule(), + new PersistenceModule() ); this.injector.injectMembers(this); @@ -323,25 +325,6 @@ public void onEnable() { LOGGER.info("Couldn't verify purchase :("); } - // Database - if (Settings.Enabled_Components.DATABASE) { - plotSquared.setupDatabase(); - } - - // Check if we need to convert old flag values, etc - if (!plotSquared.getConfigurationVersion().equalsIgnoreCase("v5")) { - // Perform upgrade - if (DBFunc.dbManager.convertFlags()) { - LOGGER.info("Flags were converted successfully!"); - // Update the config version - try { - plotSquared.setConfigurationVersion("v5"); - } catch (final Exception e) { - e.printStackTrace(); - } - } - } - // Comments CommentManager.registerDefaultInboxes(); From 4478e3fc4dc4630d1fc2f08f22ec4ac71428c9b5 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 16:07:24 +0200 Subject: [PATCH 028/141] feat: remove legacy database setup method from PlotSquared --- .../com/plotsquared/core/PlotSquared.java | 57 ------------------- 1 file changed, 57 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/PlotSquared.java b/Core/src/main/java/com/plotsquared/core/PlotSquared.java index af94ed1dde..e73b5b369b 100644 --- a/Core/src/main/java/com/plotsquared/core/PlotSquared.java +++ b/Core/src/main/java/com/plotsquared/core/PlotSquared.java @@ -1281,63 +1281,6 @@ private void checkRoadRegenPersistence() { } } - /** - * Set up the database connection. - */ - public void setupDatabase() { - try { - if (DBFunc.dbManager != null) { - DBFunc.dbManager.close(); - } - Database database; - if (Storage.MySQL.USE) { - database = new MySQL(Storage.MySQL.HOST, Storage.MySQL.PORT, Storage.MySQL.DATABASE, - Storage.MySQL.USER, Storage.MySQL.PASSWORD - ); - } else if (Storage.SQLite.USE) { - File file = FileUtils.getFile(platform.getDirectory(), Storage.SQLite.DB + ".db"); - database = new SQLite(file); - } else { - LOGGER.error("No storage type is set. Disabling PlotSquared"); - this.platform.shutdown(); //shutdown used instead of disable because no database is set - return; - } - DBFunc.dbManager = new SQLManager( - database, - Storage.PREFIX, - this.eventDispatcher, - this.plotListener, - this.worldConfiguration - ); - this.plots_tmp = DBFunc.getPlots(); - if (getPlotAreaManager() instanceof SinglePlotAreaManager) { - SinglePlotArea area = ((SinglePlotAreaManager) getPlotAreaManager()).getArea(); - addPlotArea(area); - ConfigurationSection section = worldConfiguration.getConfigurationSection("worlds.*"); - if (section == null) { - section = worldConfiguration.createSection("worlds.*"); - } - area.saveConfiguration(section); - area.loadDefaultConfiguration(section); - } - this.clustersTmp = DBFunc.getClusters(); - LOGGER.info("Connection to database established. Type: {}", Storage.MySQL.USE ? "MySQL" : "SQLite"); - } catch (ClassNotFoundException | SQLException e) { - LOGGER.error( - "Failed to open database connection ({}). Disabling PlotSquared", - Storage.MySQL.USE ? "MySQL" : "SQLite" - ); - LOGGER.error("==== Here is an ugly stacktrace, if you are interested in those things ==="); - e.printStackTrace(); - LOGGER.error("==== End of stacktrace ===="); - LOGGER.error( - "Please go to the {} 'storage.yml' and configure the database correctly", - platform.pluginName() - ); - this.platform.shutdown(); //shutdown used instead of disable because of database error - } - } - /** * Setup the default configuration. */ From 65ec881b428d8f5f43c23ec0cf72329a26b598b8 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 16:20:18 +0200 Subject: [PATCH 029/141] feat: add persistence.xml for JPA configuration --- Core/src/main/resources/META-INF/persistence.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 Core/src/main/resources/META-INF/persistence.xml diff --git a/Core/src/main/resources/META-INF/persistence.xml b/Core/src/main/resources/META-INF/persistence.xml new file mode 100644 index 0000000000..ebf0be39cf --- /dev/null +++ b/Core/src/main/resources/META-INF/persistence.xml @@ -0,0 +1,13 @@ + + + + org.hibernate.jpa.HibernatePersistenceProvider + false + + + + + From 8b690fd633c77d189513c9de2fb2a17470d76acc Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 16:20:27 +0200 Subject: [PATCH 030/141] feat: enhance PlotCommentRepository with additional methods for hashcode handling --- .../persistence/repository/api/PlotCommentRepository.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotCommentRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotCommentRepository.java index 361f26c6da..cdec0dd55e 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotCommentRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotCommentRepository.java @@ -6,7 +6,10 @@ public interface PlotCommentRepository { List findByWorldAndInbox(String world, String inbox); + List findByWorldHashAndInbox(String world, int hashcode, String inbox); void save(PlotCommentEntity entity); - void deleteOne(String world, int hashcode, String inbox, String sender); + void deleteOne(String world, int hashcode, String inbox, String sender, String comment); void clearInbox(String world, String inbox); + void clearInbox(String world, int hashcode, String inbox); + void deleteByWorldAndHash(String world, int hashcode); } From 928e22b3cf094e7155448af81419fdc26307a3f8 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 16:20:56 +0200 Subject: [PATCH 031/141] feat: update PlotCommentEntity with new named queries for enhanced data retrieval and deletion --- .../core/persistence/entity/PlotCommentEntity.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotCommentEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotCommentEntity.java index 7c8608288e..ffb6447775 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotCommentEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotCommentEntity.java @@ -13,8 +13,11 @@ @IdClass(PlotCommentId.class) @NamedQueries({ @NamedQuery(name = "PlotComment.findByWorldAndInbox", query = "SELECT c FROM PlotCommentEntity c WHERE c.world = :world AND c.inbox = :inbox ORDER BY c.timestamp DESC"), - @NamedQuery(name = "PlotComment.deleteOne", query = "DELETE FROM PlotCommentEntity c WHERE c.world = :world AND c.hashcode = :hash AND c.inbox = :inbox AND c.sender = :sender"), - @NamedQuery(name = "PlotComment.clearInbox", query = "DELETE FROM PlotCommentEntity c WHERE c.world = :world AND c.inbox = :inbox") + @NamedQuery(name = "PlotComment.findByWorldHashAndInbox", query = "SELECT c FROM PlotCommentEntity c WHERE c.world = :world AND c.hashcode = :hash AND c.inbox = :inbox ORDER BY c.timestamp DESC"), + @NamedQuery(name = "PlotComment.deleteOne", query = "DELETE FROM PlotCommentEntity c WHERE c.world = :world AND c.hashcode = :hash AND c.inbox = :inbox AND c.sender = :sender AND c.comment = :comment"), + @NamedQuery(name = "PlotComment.clearInbox", query = "DELETE FROM PlotCommentEntity c WHERE c.world = :world AND c.inbox = :inbox"), + @NamedQuery(name = "PlotComment.clearInboxByWorldHash", query = "DELETE FROM PlotCommentEntity c WHERE c.world = :world AND c.hashcode = :hash AND c.inbox = :inbox"), + @NamedQuery(name = "PlotComment.deleteByWorldAndHash", query = "DELETE FROM PlotCommentEntity c WHERE c.world = :world AND c.hashcode = :hash") }) public class PlotCommentEntity { @Id From 5b8b29d9fd2e3ed2a6bc02e3ead4fb33c2135a81 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 16:21:05 +0200 Subject: [PATCH 032/141] feat: enhance PlotCommentRepositoryJpa with new methods for inbox management and comment deletion --- .../jpa/PlotCommentRepositoryJpa.java | 60 ++++++++++++++++++- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotCommentRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotCommentRepositoryJpa.java index d84e994d78..41afbc5d31 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotCommentRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotCommentRepositoryJpa.java @@ -35,6 +35,20 @@ public List findByWorldAndInbox(String world, String inbox) { } } + @Override + public List findByWorldHashAndInbox(String world, int hashcode, String inbox) { + EntityManager em = emf.createEntityManager(); + try { + return em.createNamedQuery("PlotComment.findByWorldHashAndInbox", PlotCommentEntity.class) + .setParameter("world", world) + .setParameter("hash", hashcode) + .setParameter("inbox", inbox) + .getResultList(); + } finally { + em.close(); + } + } + @Override public void save(PlotCommentEntity entity) { EntityManager em = emf.createEntityManager(); @@ -53,7 +67,7 @@ public void save(PlotCommentEntity entity) { } @Override - public void deleteOne(String world, int hashcode, String inbox, String sender) { + public void deleteOne(String world, int hashcode, String inbox, String sender, String comment) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); try { @@ -63,11 +77,12 @@ public void deleteOne(String world, int hashcode, String inbox, String sender) { .setParameter("hash", hashcode) .setParameter("inbox", inbox) .setParameter("sender", sender) + .setParameter("comment", comment) .executeUpdate(); tx.commit(); } catch (RuntimeException e) { if (tx.isActive()) tx.rollback(); - LOGGER.error("Failed to delete one plot comment (world={}, inbox={}, hashcode={}, sender={})", world, inbox, hashcode, sender, e); + LOGGER.error("Failed to delete one plot comment (world={}, inbox={}, hashcode={}, sender={}, comment={})", world, inbox, hashcode, sender, comment, e); throw e; } finally { em.close(); @@ -93,4 +108,45 @@ public void clearInbox(String world, String inbox) { em.close(); } } + + @Override + public void clearInbox(String world, int hashcode, String inbox) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + em.createNamedQuery("PlotComment.clearInboxByWorldHash") + .setParameter("world", world) + .setParameter("hash", hashcode) + .setParameter("inbox", inbox) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to clear inbox by world+hash (world={}, hashcode={}, inbox={})", world, hashcode, inbox, e); + throw e; + } finally { + em.close(); + } + } + + @Override + public void deleteByWorldAndHash(String world, int hashcode) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + em.createNamedQuery("PlotComment.deleteByWorldAndHash") + .setParameter("world", world) + .setParameter("hash", hashcode) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to delete comments by world and hash (world={}, hashcode={})", world, hashcode, e); + throw e; + } finally { + em.close(); + } + } } From 3339111af2ca2f9f2c043635c71d7c02a2ed0a43 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 16:21:13 +0200 Subject: [PATCH 033/141] feat: enhance Flyway configuration for JPA migration with placeholders and safety features --- .../core/persistence/config/PersistenceModule.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java b/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java index 249c5810c5..bbcf3acac1 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java @@ -83,10 +83,22 @@ Flyway provideFlyway() { } else { url = "jdbc:sqlite:" + Storage.SQLite.DB + ".db"; } + // Support prefixed table names in SQL migrations via placeholders + Map placeholders = new java.util.HashMap<>(); + placeholders.put("prefix", Storage.PREFIX == null ? "" : Storage.PREFIX); + return Flyway.configure() .dataSource(url, user, pass) .locations("classpath:db/migration") + // Baseline an existing, unversioned schema to avoid destructive changes .baselineOnMigrate(true) + .baselineVersion("0") + .baselineDescription("Baseline before migrating to JPA-managed schema") + // Prevent accidental data loss + .cleanDisabled(true) + // Enable ${prefix} usage in SQL files for table names + .placeholderReplacement(true) + .placeholders(placeholders) .load(); } } From 82b101b074c4bd1db5db98020cf5f0de58b0f0ab Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Thu, 4 Sep 2025 16:21:26 +0200 Subject: [PATCH 034/141] feat: refactor DBFunc to utilize PlayerMetaRepository and PlotCommentRepository for persistent metadata management --- .../com/plotsquared/core/database/DBFunc.java | 127 +++++++++++++----- 1 file changed, 97 insertions(+), 30 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java index 1b8ede36a3..19401e4ed9 100644 --- a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java +++ b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java @@ -18,6 +18,11 @@ */ package com.plotsquared.core.database; +import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.persistence.entity.PlayerMetaEntity; +import com.plotsquared.core.persistence.entity.PlotCommentEntity; +import com.plotsquared.core.persistence.repository.api.PlayerMetaRepository; +import com.plotsquared.core.persistence.repository.api.PlotCommentRepository; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotCluster; @@ -54,41 +59,49 @@ public class DBFunc { */ public static AbstractDB dbManager; - public static void updateTables(int[] oldVersion) { - if (dbManager != null) { - dbManager.updateTables(oldVersion); - } - } - public static void addPersistentMeta(UUID uuid, String key, byte[] meta, boolean delete) { - if (dbManager != null) { - dbManager.addPersistentMeta(uuid, key, meta, delete); + try { + PlayerMetaRepository repo = PlotSquared.platform().injector().getInstance(PlayerMetaRepository.class); + if (delete) { + repo.delete(uuid.toString(), key); + } else { + repo.put(uuid.toString(), key, meta); + } + } catch (Throwable ignored) { } } public static void getPersistentMeta(UUID uuid, RunnableVal> result) { - if (dbManager != null) { - dbManager.getPersistentMeta(uuid, result); + try { + PlayerMetaRepository repo = PlotSquared.platform().injector().getInstance(PlayerMetaRepository.class); + Map map = new HashMap<>(); + for (PlayerMetaEntity e : repo.findByUuid(uuid.toString())) { + map.put(e.getKey(), e.getValue()); + } + if (result != null) { + result.run(map); + } + } catch (Throwable t) { + if (result != null) { + result.run(new HashMap<>()); + } } } public static void removePersistentMeta(UUID uuid, String key) { - if (dbManager != null) { - dbManager.removePersistentMeta(uuid, key); + try { + PlayerMetaRepository repo = PlotSquared.platform().injector().getInstance(PlayerMetaRepository.class); + repo.delete(uuid.toString(), key); + } catch (Throwable ignored) { } } public static CompletableFuture swapPlots(Plot plot1, Plot plot2) { - if (dbManager != null) { - return dbManager.swapPlots(plot1, plot2); + if (dbManager == null || plot1 == null || plot2 == null || plot1.temp == -1 || plot2.temp == -1) { + return CompletableFuture.completedFuture(false); } - return CompletableFuture.completedFuture(false); - } - - public static boolean deleteTables() { - return dbManager != null && dbManager.deleteTables(); + return DBFunc.dbManager.swapPlots(plot1, plot2); } - public static void movePlot(Plot originalPlot, Plot newPlot) { if (originalPlot.temp == -1 || newPlot.temp == -1) { return; @@ -255,10 +268,16 @@ public static void deleteDenied(Plot plot) { * @param plot */ public static void deleteComments(Plot plot) { - if (plot.temp == -1 || dbManager == null) { + if (plot.temp == -1) { return; } - DBFunc.dbManager.deleteComments(plot); + try { + com.plotsquared.core.persistence.repository.api.PlotCommentRepository repo = PlotSquared.platform().injector().getInstance(com.plotsquared.core.persistence.repository.api.PlotCommentRepository.class); + String world = plot.getArea().toString(); + int hash = plot.getId().hashCode(); + repo.deleteByWorldAndHash(world, hash); + } catch (Throwable ignored) { + } } /** @@ -382,17 +401,33 @@ public static void setPosition(Plot plot, String position) { * @param comment */ public static void removeComment(Plot plot, PlotComment comment) { - if (plot.temp == -1 || dbManager == null) { + if (plot.temp == -1) { return; } - DBFunc.dbManager.removeComment(plot, comment); + try { + PlotCommentRepository repo = PlotSquared.platform().injector().getInstance(PlotCommentRepository.class); + String world = plot.getArea().toString(); + int hash = plot.getId().hashCode(); + repo.deleteOne(world, hash, comment.inbox(), comment.senderName(), comment.comment()); + } catch (Throwable ignored) { + } } public static void clearInbox(Plot plot, String inbox) { - if (plot != null && plot.temp == -1 || dbManager == null) { + if (plot != null && plot.temp == -1) { return; } - DBFunc.dbManager.clearInbox(plot, inbox); + try { + PlotCommentRepository repo = PlotSquared.platform().injector().getInstance(PlotCommentRepository.class); + if (plot != null) { + String world = plot.getArea().toString(); + int hash = plot.getId().hashCode(); + repo.clearInbox(world, hash, inbox); + } else { + // Fallback: no plot provided; unable to infer world. No-op to avoid unintended global deletions. + } + } catch (Throwable ignored) { + } } /** @@ -400,10 +435,23 @@ public static void clearInbox(Plot plot, String inbox) { * @param comment */ public static void setComment(Plot plot, PlotComment comment) { - if (plot != null && plot.temp == -1 || dbManager == null) { + if (plot != null && plot.temp == -1) { return; } - DBFunc.dbManager.setComment(plot, comment); + try { + PlotCommentRepository repo = PlotSquared.platform().injector().getInstance(PlotCommentRepository.class); + if (plot != null) { + PlotCommentEntity entity = new PlotCommentEntity(); + entity.setWorld(plot.getArea().toString()); + entity.setHashcode(plot.getId().hashCode()); + entity.setComment(comment.comment()); + entity.setInbox(comment.inbox()); + entity.setTimestamp((int) (comment.timestamp() / 1000)); + entity.setSender(comment.senderName()); + repo.save(entity); + } + } catch (Throwable ignored) { + } } /** @@ -413,10 +461,29 @@ public static void getComments( Plot plot, String inbox, RunnableVal> whenDone ) { - if (plot != null && plot.temp == -1 || dbManager == null) { + if (plot != null && plot.temp == -1) { return; } - DBFunc.dbManager.getComments(plot, inbox, whenDone); + try { + PlotCommentRepository repo = PlotSquared.platform().injector().getInstance(PlotCommentRepository.class); + List out = new java.util.ArrayList<>(); + if (plot != null) { + String world = plot.getArea().toString(); + int hash = plot.getId().hashCode(); + for (PlotCommentEntity e : repo.findByWorldHashAndInbox(world, hash, inbox)) { + PlotId id = (e.getHashcode() != null && e.getHashcode() != 0) ? PlotId.unpair(e.getHashcode()) : null; + long tsMillis = e.getTimestamp() != null ? e.getTimestamp().longValue() * 1000L : 0L; + out.add(new PlotComment(e.getWorld(), id, e.getComment(), e.getSender(), e.getInbox(), tsMillis)); + } + } + if (whenDone != null) { + whenDone.run(out); + } + } catch (Throwable t) { + if (whenDone != null) { + whenDone.run(java.util.Collections.emptyList()); + } + } } /** From 0345265d81d4510fa636e63459c552c47e468c0e Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Thu, 4 Sep 2025 19:12:15 +0200 Subject: [PATCH 035/141] feat: add repository interfaces for cluster and plot management with CRUD operations --- .../api/ClusterHelperRepository.java | 27 +++++++ .../api/ClusterInvitedRepository.java | 26 +++++++ .../repository/api/ClusterRepository.java | 39 ++++++++++ .../repository/api/PlayerMetaRepository.java | 25 +++++++ .../repository/api/PlotCommentRepository.java | 60 +++++++++++++++ .../repository/api/PlotDeniedRepository.java | 27 +++++++ .../repository/api/PlotFlagRepository.java | 31 ++++++++ .../api/PlotMembershipRepository.java | 25 +++++++ .../repository/api/PlotRatingRepository.java | 18 +++++ .../repository/api/PlotRepository.java | 74 +++++++++++++++++++ .../api/PlotSettingsRepository.java | 21 ++++++ .../repository/api/PlotTrustedRepository.java | 26 +++++++ 12 files changed, 399 insertions(+) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterHelperRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterHelperRepository.java index 9a08fe0ac0..18589de9e6 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterHelperRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterHelperRepository.java @@ -2,8 +2,35 @@ import java.util.List; +/** + * Repository abstraction for managing helper users associated with a cluster. + * Implementations are responsible for persisting and retrieving associations + * between a cluster and player UUIDs who act as helpers. + */ public interface ClusterHelperRepository { + /** + * Retrieves all helper user UUIDs associated with the given cluster. + * + * @param clusterId the unique identifier of the cluster + * @return list of helper user UUIDs (as String), never null; may be empty + */ List findUsers(long clusterId); + + /** + * Adds the given user as a helper to the specified cluster. + * Implementations should be idempotent: adding an existing association + * should not create duplicates nor fail. + * + * @param clusterId the unique identifier of the cluster + * @param userUuid the helper user's UUID (String representation) + */ void add(long clusterId, String userUuid); + + /** + * Removes the given user from the helpers of the specified cluster. + * + * @param clusterId the unique identifier of the cluster + * @param userUuid the helper user's UUID (String representation) + */ void remove(long clusterId, String userUuid); } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterInvitedRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterInvitedRepository.java index 6710eb80b9..89bbf8cbab 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterInvitedRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterInvitedRepository.java @@ -2,8 +2,34 @@ import java.util.List; +/** + * Repository abstraction for managing invited users for a cluster. + * Implementations persist associations between clusters and player UUIDs + * that have been invited to the cluster but may not yet be members/helpers. + */ public interface ClusterInvitedRepository { + /** + * Retrieves all invited user UUIDs for the given cluster. + * + * @param clusterId the unique identifier of the cluster + * @return list of invited user UUIDs (as String), never null; may be empty + */ List findUsers(long clusterId); + + /** + * Records an invitation of the given user to the specified cluster. + * Implementations should treat duplicate invitations idempotently. + * + * @param clusterId the unique identifier of the cluster + * @param userUuid the invited user's UUID (String representation) + */ void add(long clusterId, String userUuid); + + /** + * Revokes an invitation for the given user from the specified cluster. + * + * @param clusterId the unique identifier of the cluster + * @param userUuid the invited user's UUID (String representation) + */ void remove(long clusterId, String userUuid); } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterRepository.java index 104c38d004..821fb81307 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterRepository.java @@ -5,10 +5,49 @@ import java.util.List; import java.util.Optional; +/** + * Repository for managing ClusterEntity persistence and lookups. + */ public interface ClusterRepository { + /** + * Finds a cluster by its primary identifier. + * + * @param id the cluster id + * @return an Optional containing the ClusterEntity if found, otherwise empty + */ Optional findById(long id); + + /** + * Finds the cluster by world and a coordinate that lies within the cluster bounds. + * Exact semantics depend on implementation; typically returns the cluster that contains + * the given x/z coordinate in the specified world. + * + * @param world the world name + * @param x x-coordinate (plot coordinate or block coordinate as defined by implementation) + * @param z z-coordinate (plot coordinate or block coordinate as defined by implementation) + * @return an Optional containing the ClusterEntity if a match is found; otherwise empty + */ Optional findByWorldAndBounds(String world, int x, int z); + + /** + * Returns all clusters in a given world. + * + * @param world the world name + * @return list of clusters, never null; may be empty + */ List findByWorld(String world); + + /** + * Persists the given cluster. Implementations may insert or update as needed. + * + * @param cluster the cluster entity to save + */ void save(ClusterEntity cluster); + + /** + * Deletes the cluster with the specified id. No-op if it does not exist. + * + * @param id the cluster id + */ void deleteById(long id); } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlayerMetaRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlayerMetaRepository.java index 15ce9b25b7..25e85beecf 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlayerMetaRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlayerMetaRepository.java @@ -4,8 +4,33 @@ import java.util.List; +/** + * Repository for storing and retrieving arbitrary metadata entries for players. + * Keys are namespaced per player UUID and map to binary values. + */ public interface PlayerMetaRepository { + /** + * Returns all metadata entries for the player with the given UUID. + * + * @param uuid the player's UUID (String representation) + * @return list of metadata entries, never null; may be empty + */ List findByUuid(String uuid); + + /** + * Inserts or updates a metadata value for the given player and key. + * + * @param uuid the player's UUID (String representation) + * @param key the metadata key + * @param value the value as a byte array; implementations may store as-is + */ void put(String uuid, String key, byte[] value); + + /** + * Deletes a metadata entry for the given player and key. No-op if absent. + * + * @param uuid the player's UUID (String representation) + * @param key the metadata key + */ void delete(String uuid, String key); } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotCommentRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotCommentRepository.java index cdec0dd55e..8151f2868f 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotCommentRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotCommentRepository.java @@ -4,12 +4,72 @@ import java.util.List; +/** + * Repository for managing plot comments, typically grouped by "inbox" names + * (e.g., inbox types). Methods support querying by world, by plot hash, and + * by inbox, as well as adding and removing comments. + */ public interface PlotCommentRepository { + /** + * Returns all comments for a given world and inbox across all plots. + * + * @param world the world name + * @param inbox the inbox identifier/category + * @return list of comments, never null; may be empty + */ List findByWorldAndInbox(String world, String inbox); + + /** + * Returns all comments for a specific plot (identified by hash) in a world and inbox. + * + * @param world the world name + * @param hashcode the plot hash identifier + * @param inbox the inbox identifier/category + * @return list of comments, never null; may be empty + */ List findByWorldHashAndInbox(String world, int hashcode, String inbox); + + /** + * Persists a comment entity (insert). + * + * @param entity the comment entity to save + */ void save(PlotCommentEntity entity); + + /** + * Deletes a single comment by its identifying fields. + * + * @param world the world name + * @param hashcode the plot hash identifier + * @param inbox the inbox identifier/category + * @param sender the comment sender (UUID or name as stored) + * @param comment the exact comment text + */ void deleteOne(String world, int hashcode, String inbox, String sender, String comment); + + /** + * Clears all comments in the given world for the specified inbox across all plots. + * + * @param world the world name + * @param inbox the inbox identifier/category + */ void clearInbox(String world, String inbox); + + /** + * Clears all comments for a specific plot (by hash) in the given world and inbox. + * + * @param world the world name + * @param hashcode the plot hash identifier + * @param inbox the inbox identifier/category + */ void clearInbox(String world, int hashcode, String inbox); + + /** + * Deletes all comments associated with a specific plot (by hash) in a world, + * regardless of inbox. + * + * @param world the world name + * @param hashcode the plot hash identifier + */ void deleteByWorldAndHash(String world, int hashcode); } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotDeniedRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotDeniedRepository.java index ac2248539f..852bb3bf2c 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotDeniedRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotDeniedRepository.java @@ -2,8 +2,35 @@ import java.util.List; +/** + * Repository for managing denied users for a plot. + * Denied users are explicitly prevented from interacting with or entering the plot + * depending on gameplay rules. This repository stores associations between plot ids + * and player UUIDs. + */ public interface PlotDeniedRepository { + /** + * Retrieves all denied user UUIDs for the given plot. + * + * @param plotId the unique identifier of the plot + * @return list of denied user UUIDs (as String), never null; may be empty + */ List findUsers(long plotId); + + /** + * Adds the given user to the denied list of the specified plot. + * Implementations should be idempotent and avoid duplicates. + * + * @param plotId the unique identifier of the plot + * @param userUuid the user's UUID (String representation) + */ void add(long plotId, String userUuid); + + /** + * Removes the given user from the denied list of the specified plot. + * + * @param plotId the unique identifier of the plot + * @param userUuid the user's UUID (String representation) + */ void remove(long plotId, String userUuid); } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotFlagRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotFlagRepository.java index f7c8f7032c..626a94ca13 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotFlagRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotFlagRepository.java @@ -5,9 +5,40 @@ import java.util.List; import java.util.Optional; +/** + * Repository for managing flags associated with a plot. + * A flag is a named configuration entry applied to an individual plot. + */ public interface PlotFlagRepository { + /** + * Retrieves all flags for a given plot. + * + * @param plotId the plot identifier + * @return list of plot flags, never null; may be empty + */ List findByPlotId(long plotId); + + /** + * Retrieves a specific flag by name for the given plot. + * + * @param plotId the plot identifier + * @param flagName the flag name + * @return Optional with the flag if present; otherwise empty + */ Optional findByPlotAndName(long plotId, String flagName); + + /** + * Persists the flag entity. Implementations may insert or update as needed. + * + * @param entity the flag entity to save + */ void save(PlotFlagEntity entity); + + /** + * Deletes the flag with the given name from the specified plot. + * + * @param plotId the plot identifier + * @param flagName the flag name + */ void deleteByPlotAndName(long plotId, String flagName); } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotMembershipRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotMembershipRepository.java index f4dca3b896..891f9bf98d 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotMembershipRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotMembershipRepository.java @@ -2,8 +2,33 @@ import java.util.List; +/** + * Repository for managing plot member associations. + * Members typically have elevated permissions on the plot compared to visitors. + */ public interface PlotMembershipRepository { + /** + * Retrieves all member user UUIDs for the given plot. + * + * @param plotId the unique identifier of the plot + * @return list of member user UUIDs (as String), never null; may be empty + */ List findUsers(long plotId); + + /** + * Adds the given user as a member of the specified plot. + * Implementations should be idempotent and avoid duplicates. + * + * @param plotId the unique identifier of the plot + * @param userUuid the user's UUID (String representation) + */ void add(long plotId, String userUuid); + + /** + * Removes the given user from the members of the specified plot. + * + * @param plotId the unique identifier of the plot + * @param userUuid the user's UUID (String representation) + */ void remove(long plotId, String userUuid); } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRatingRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRatingRepository.java index 161cb68089..813563b2d4 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRatingRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRatingRepository.java @@ -4,7 +4,25 @@ import java.util.List; +/** + * Repository for managing player ratings of plots. + */ public interface PlotRatingRepository { + /** + * Retrieves all rating entries for the given plot. + * + * @param plotId the plot identifier + * @return list of plot ratings, never null; may be empty + */ List findByPlotId(long plotId); + + /** + * Inserts a new rating or updates the existing rating for the given player on the plot. + * The rating scale is defined by the caller/implementation. + * + * @param plotId the plot identifier + * @param playerUuid the player's UUID (String representation) + * @param rating the rating value to set + */ void upsert(long plotId, String playerUuid, int rating); } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java index 012c2ba887..e1932e85f7 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java @@ -1,15 +1,89 @@ package com.plotsquared.core.persistence.repository.api; import com.plotsquared.core.persistence.entity.PlotEntity; +import com.plotsquared.core.plot.Plot; import java.util.List; import java.util.Optional; +import java.util.UUID; +/** + * Repository abstraction for reading and writing plot data and related + * lookups by id, world, owner, and coordinates. + */ public interface PlotRepository { + /** + * Swaps the persisted state of two plots. + * Implementations should ensure the swap occurs atomically/consistently + * if the underlying storage supports transactions. + * + * @param plot1 the first plot + * @param plot2 the second plot + * @return true if the swap succeeded; false otherwise + */ + boolean swapPlots(Plot plot1, Plot plot2); + + void movePlots(Plot originPlot, Plot newPlot); + + void setOwner(Plot plot, UUID newOwner); + + /** + * Finds a plot by its primary identifier. + * + * @param id the plot id + * @return an Optional with the plot entity if found; otherwise empty + */ Optional findById(long id); + + /** + * Finds a plot by its x and z coordinates. + * The exact semantics are implementation-defined; despite the name, some + * implementations may also use the provided world hint. + * + * @param x plot x-id (not block coordinate) + * @param z plot z-id (not block coordinate) + * @param world an optional world hint depending on implementation + * @return an Optional with the plot entity if found; otherwise empty + */ + Optional findByXAndZAnyWorld(int x, int z, String world); + + /** + * Finds a plot by world and plot coordinates. + * + * @param world the world name + * @param x plot x-id (not block coordinate) + * @param z plot z-id (not block coordinate) + * @return an Optional with the plot entity if found; otherwise empty + */ Optional findByWorldAndId(String world, int x, int z); + + /** + * Finds all plots owned by the given player. + * + * @param ownerUuid the owner's UUID (String representation) + * @return list of plots, never null; may be empty + */ List findByOwner(String ownerUuid); + + /** + * Finds all plots in the specified world. + * + * @param world the world name + * @return list of plots, never null; may be empty + */ List findByWorld(String world); + + /** + * Persists the given plot entity (insert or update). + * + * @param plot the plot entity to save + */ void save(PlotEntity plot); + + /** + * Deletes the plot with the specified id. No-op if it does not exist. + * + * @param id the plot id + */ void deleteById(long id); } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotSettingsRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotSettingsRepository.java index eb845e6b31..395845752c 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotSettingsRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotSettingsRepository.java @@ -4,8 +4,29 @@ import java.util.Optional; +/** + * Repository for persisting and retrieving per-plot settings. + */ public interface PlotSettingsRepository { + /** + * Retrieves the settings for the given plot if available. + * + * @param plotId the plot identifier + * @return Optional with the settings if present; otherwise empty + */ Optional findByPlotId(long plotId); + + /** + * Persists the provided settings entity (insert or update). + * + * @param settings the settings entity to save + */ void save(PlotSettingsEntity settings); + + /** + * Deletes the settings associated with the specified plot id. No-op if absent. + * + * @param plotId the plot identifier + */ void deleteByPlotId(long plotId); } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotTrustedRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotTrustedRepository.java index ec1d34afa2..fe2283092f 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotTrustedRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotTrustedRepository.java @@ -2,8 +2,34 @@ import java.util.List; +/** + * Repository for managing trusted users for a plot. + * Trusted users typically have broader permissions than helpers but may be + * distinct from owners and members depending on server policy. + */ public interface PlotTrustedRepository { + /** + * Retrieves all trusted user UUIDs for the given plot. + * + * @param plotId the unique identifier of the plot + * @return list of trusted user UUIDs (as String), never null; may be empty + */ List findUsers(long plotId); + + /** + * Adds the given user to the trusted list of the specified plot. + * Implementations should be idempotent and avoid duplicates. + * + * @param plotId the unique identifier of the plot + * @param userUuid the user's UUID (String representation) + */ void add(long plotId, String userUuid); + + /** + * Removes the given user from the trusted list of the specified plot. + * + * @param plotId the unique identifier of the plot + * @param userUuid the user's UUID (String representation) + */ void remove(long plotId, String userUuid); } From ac778ac8e25ae93cad092dffa94a0ce930a6b2b9 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Thu, 4 Sep 2025 19:12:22 +0200 Subject: [PATCH 036/141] fix: remove unnecessary database connection closure in PlotSquared --- Core/src/main/java/com/plotsquared/core/PlotSquared.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/PlotSquared.java b/Core/src/main/java/com/plotsquared/core/PlotSquared.java index e73b5b369b..324631c23e 100644 --- a/Core/src/main/java/com/plotsquared/core/PlotSquared.java +++ b/Core/src/main/java/com/plotsquared/core/PlotSquared.java @@ -1234,9 +1234,6 @@ public void disable() { } catch (final Exception ignored) { } DBFunc.validatePlots(plots); - - // Close the connection - DBFunc.close(); } catch (NullPointerException throwable) { LOGGER.error("Could not close database connection", throwable); throwable.printStackTrace(); From 7b901b98cc3d471061664e1b28f98e5d64811033 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Thu, 4 Sep 2025 19:12:30 +0200 Subject: [PATCH 037/141] feat: implement plot swapping and moving functionality in PlotRepositoryJpa --- .../repository/jpa/PlotRepositoryJpa.java | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java index 5edcab1bc0..aa9cba95bb 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java @@ -3,6 +3,7 @@ import com.google.inject.Inject; import com.plotsquared.core.persistence.entity.PlotEntity; import com.plotsquared.core.persistence.repository.api.PlotRepository; +import com.plotsquared.core.plot.Plot; import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManagerFactory; import jakarta.persistence.EntityTransaction; @@ -11,6 +12,7 @@ import java.util.List; import java.util.Optional; +import java.util.UUID; public class PlotRepositoryJpa implements PlotRepository { @@ -23,6 +25,73 @@ public PlotRepositoryJpa(EntityManagerFactory emf) { this.emf = emf; } + @Override + public boolean swapPlots(final Plot plot1, final Plot plot2) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + var plot1Id = findByXAndZAnyWorld(plot1.getId().getX(), plot1.getId().getY(), plot1.getWorldName()).orElseThrow().getId(); + var plot2Id = findByXAndZAnyWorld(plot2.getId().getX(), plot2.getId().getY(), plot2.getWorldName()).orElseThrow().getId(); + em.createNamedQuery("Plot.updateXANDZ") + .setParameter("id", plot1Id) + .setParameter("x", plot1.getId().getX()) + .setParameter("z", plot1.getId().getY()); + em.createNamedQuery("Plot.updateXANDZ") + .setParameter("id", plot2Id) + .setParameter("x", plot2.getId().getX()) + .setParameter("z", plot2.getId().getY()); + tx.commit(); + return true; + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + } + return false; + } + + @Override + public void movePlots(final Plot originPlot, final Plot newPlot) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + var originPlotId = findByXAndZAnyWorld( + originPlot.getId().getX(), + originPlot.getId().getY(), + originPlot.getWorldName() + ).orElseThrow().getId(); + em.createNamedQuery("Plot.movePlot") + .setParameter("id", originPlotId) + .setParameter("plotIdX", newPlot.getId().getX()) + .setParameter("plotIdZ", newPlot.getId().getY()) + .setParameter("world", newPlot.getWorldName()); + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to move plots (plot1={}, plot2={})", originPlot, newPlot, e); + throw e; + } + } + + @Override + public void setOwner(final Plot plot, final UUID newOwner) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + em.createNamedQuery("Plot.setOwner") + .setParameter("world", plot.getWorldName()) + .setParameter("x", plot.getId().getX()) + .setParameter("z", plot.getId().getY()) + .setParameter("owner", newOwner); + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to set plot owner (plot={}, newOwner={})", plot, newOwner, e); + throw e; + } + } + @Override public Optional findById(long id) { EntityManager em = emf.createEntityManager(); @@ -33,6 +102,20 @@ public Optional findById(long id) { } } + @Override + public Optional findByXAndZAnyWorld(final int x, final int z, final String world) { + EntityManager em = emf.createEntityManager(); + try { + return em.createNamedQuery("Plot.findByXAndZAndWorld", PlotEntity.class) + .setParameter("x", x) + .setParameter("z", z) + .setParameter("world", world) + .getResultStream().findFirst(); + } finally { + em.close(); + } + } + @Override public Optional findByWorldAndId(String world, int x, int z) { EntityManager em = emf.createEntityManager(); From fe0924b999fe5e7f38664ac4fa03fba0f81da465 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Thu, 4 Sep 2025 19:12:34 +0200 Subject: [PATCH 038/141] feat: add new named queries for plot management in PlotEntity --- .../core/persistence/entity/PlotEntity.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotEntity.java index 19b77a9ed5..0169d7b1ae 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotEntity.java @@ -17,7 +17,18 @@ @NamedQueries({ @NamedQuery(name = "Plot.findByWorldAndId", query = "SELECT p FROM PlotEntity p WHERE p.world = :world AND p.plotIdX = :x AND p.plotIdZ = :z"), @NamedQuery(name = "Plot.findByOwner", query = "SELECT p FROM PlotEntity p WHERE p.owner = :owner"), - @NamedQuery(name = "Plot.findByWorld", query = "SELECT p FROM PlotEntity p WHERE p.world = :world") + @NamedQuery(name = "Plot.findByWorld", query = "SELECT p FROM PlotEntity p WHERE p.world = :world"), + @NamedQuery( + name = "Plot.updateXANDZ", + query = "UPDATE PlotEntity p SET p.plotIdX = :x, p.plotIdZ = :z WHERE p.id = :id" + ), + @NamedQuery(name = "Plot.findByXAndZAndWorld", query = "SELECT p FROM PlotEntity p WHERE p.plotIdX = :x AND p.plotIdZ = :z AND " + + "world = :world order by timestamp asc "), + @NamedQuery( + name = "Plot.movePlot", + query = "UPDATE PlotEntity p SET p.plotIdX = :plotIdX, p.plotIdZ = :plotIdZ, p.world = :world WHERE p.id = :id" + ), + @NamedQuery(name = "Plot.setOwner", query = "UPDATE PlotEntity p SET p.owner = :owner WHERE p.world = :world AND p.plotIdX = :x AND p.plotIdZ = :z"), }) public class PlotEntity { @Id From df90d513a19361cd79137c525168505d478d02d0 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Thu, 4 Sep 2025 19:12:39 +0200 Subject: [PATCH 039/141] feat: refactor plot management methods to use PlotRepository for improved database interactions --- .../com/plotsquared/core/database/DBFunc.java | 58 ++++--------------- 1 file changed, 11 insertions(+), 47 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java index 19401e4ed9..9faf0a42e4 100644 --- a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java +++ b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java @@ -23,6 +23,7 @@ import com.plotsquared.core.persistence.entity.PlotCommentEntity; import com.plotsquared.core.persistence.repository.api.PlayerMetaRepository; import com.plotsquared.core.persistence.repository.api.PlotCommentRepository; +import com.plotsquared.core.persistence.repository.api.PlotRepository; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotCluster; @@ -97,18 +98,22 @@ public static void removePersistentMeta(UUID uuid, String key) { } public static CompletableFuture swapPlots(Plot plot1, Plot plot2) { - if (dbManager == null || plot1 == null || plot2 == null || plot1.temp == -1 || plot2.temp == -1) { + if (plot1 == null || plot2 == null) { return CompletableFuture.completedFuture(false); } - return DBFunc.dbManager.swapPlots(plot1, plot2); + PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + return CompletableFuture.completedFuture(repo.swapPlots(plot1, plot2)); } + public static void movePlot(Plot originalPlot, Plot newPlot) { - if (originalPlot.temp == -1 || newPlot.temp == -1) { + if (originalPlot == null || newPlot == null) { return; } - DBFunc.dbManager.movePlot(originalPlot, newPlot); + PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + repo.movePlots(originalPlot, newPlot); } + @Deprecated(forRemoval = true) public static void validatePlots(Set plots) { if (dbManager == null) { return; @@ -116,32 +121,6 @@ public static void validatePlots(Set plots) { DBFunc.dbManager.validateAllPlots(plots); } - - //TODO Consider Removal - - /** - * Check if a {@link ResultSet} contains a column. - * - * @param resultSet - * @param name - * @return - */ - @Deprecated - public static boolean hasColumn(ResultSet resultSet, String name) { - try { - ResultSetMetaData meta = resultSet.getMetaData(); - int count = meta.getColumnCount(); - for (int x = 1; x <= count; x++) { - if (name.equals(meta.getColumnName(x))) { - return true; - } - } - return false; - } catch (SQLException ignored) { - return false; - } - } - /** * Set the owner of a plot * @@ -149,10 +128,8 @@ public static boolean hasColumn(ResultSet resultSet, String name) { * @param uuid New Owner */ public static void setOwner(Plot plot, UUID uuid) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.setOwner(plot, uuid); + PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + repo.setOwner(plot, uuid); } /** @@ -645,19 +622,6 @@ public static void replaceWorld(String oldWorld, String newWorld, PlotId min, Pl DBFunc.dbManager.replaceWorld(oldWorld, newWorld, min, max); } - /** - * Replace all occurrences of a uuid in the database with another one - * - * @param old - * @param now - */ - public static void replaceUUID(UUID old, UUID now) { - if (dbManager == null) { - return; - } - DBFunc.dbManager.replaceUUID(old, now); - } - public static void close() { if (dbManager != null) { DBFunc.dbManager.close(); From 8cb5c9a200f482e3d9a09789741edc8694ae61a0 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Thu, 4 Sep 2025 19:24:46 +0200 Subject: [PATCH 040/141] feat: implement bulk creation of plots and associated data in PlotRepository --- .../com/plotsquared/core/database/DBFunc.java | 7 +- .../repository/api/PlotRepository.java | 8 ++ .../repository/jpa/PlotRepositoryJpa.java | 112 ++++++++++++++++++ 3 files changed, 123 insertions(+), 4 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java index 9faf0a42e4..9273acb1f4 100644 --- a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java +++ b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java @@ -138,10 +138,9 @@ public static void setOwner(Plot plot, UUID uuid) { * @param plots List containing all plot objects */ public static void createPlotsAndData(List plots, Runnable whenDone) { - if (dbManager == null) { - return; - } - DBFunc.dbManager.createPlotsAndData(plots, whenDone); + PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + repo.createPlotsAndData(plots); + if (whenDone != null) whenDone.run(); } public static void createPlotSafe( diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java index e1932e85f7..3beb6f5690 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java @@ -27,6 +27,14 @@ public interface PlotRepository { void setOwner(Plot plot, UUID newOwner); + /** + * Bulk-creates plots and associated data (settings, flags, memberships) + * in a single transactional operation. + * + * @param plots list of plots to persist + */ + void createPlotsAndData(List plots); + /** * Finds a plot by its primary identifier. * diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java index aa9cba95bb..91349c1f6a 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java @@ -25,6 +25,118 @@ public PlotRepositoryJpa(EntityManagerFactory emf) { this.emf = emf; } + @Override + public void createPlotsAndData(final List plots) { + if (plots == null || plots.isEmpty()) { + return; + } + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + for (final Plot plot : plots) { + // Persist plot row + PlotEntity pe = new PlotEntity(); + pe.setPlotIdX(plot.getId().getX()); + pe.setPlotIdZ(plot.getId().getY()); + java.util.UUID ownerUuid = null; + try { ownerUuid = plot.getOwnerAbs(); } catch (Throwable ignored) {} + pe.setOwner(ownerUuid != null ? ownerUuid.toString() : com.plotsquared.core.database.DBFunc.EVERYONE.toString()); + // Prefer world name for consistency with other queries + String world = null; + try { world = plot.getWorldName(); } catch (Throwable ignored) {} + if (world == null) { world = plot.getArea().toString(); } + pe.setWorld(world); + em.persist(pe); + em.flush(); // ensure ID is generated + + long plotId = pe.getId(); + + // Persist settings (alias, merged, position) similar to legacy behavior + try { + var ps = plot.getSettings(); + if (ps != null) { + com.plotsquared.core.persistence.entity.PlotSettingsEntity se = new com.plotsquared.core.persistence.entity.PlotSettingsEntity(); + se.setPlot(pe); + String alias = ps.getAlias(); + if (alias != null && !alias.isEmpty()) { + se.setAlias(alias); + } + boolean[] merged = ps.getMerged(); + if (merged != null) { + int hash = com.plotsquared.core.util.HashUtil.hash(merged); + se.setMerged(hash); + } + var loc = ps.getPosition(); + String position = "DEFAULT"; + if (loc != null) { + if (loc.getY() == 0) { + position = "DEFAULT"; + } else { + position = loc.getX() + "," + loc.getY() + "," + loc.getZ(); + } + } + se.setPosition(position); + em.persist(se); + } + } catch (Throwable t) { + // log and continue + LOGGER.warn("Failed to persist settings for plot (x={}, z={}, world={})", plot.getId().getX(), plot.getId().getY(), world, t); + } + + // Persist flags + try { + var flagContainer = plot.getFlagContainer(); + if (flagContainer != null && flagContainer.getFlagMap() != null) { + for (var flagEntry : flagContainer.getFlagMap().values()) { + com.plotsquared.core.persistence.entity.PlotFlagEntity fe = new com.plotsquared.core.persistence.entity.PlotFlagEntity(); + fe.setPlot(pe); + fe.setFlag(flagEntry.getName()); + fe.setValue(flagEntry.toString()); + em.persist(fe); + } + } + } catch (Throwable t) { + LOGGER.warn("Failed to persist flags for plot (x={}, z={}, world={})", plot.getId().getX(), plot.getId().getY(), world, t); + } + + // Persist tiers: NOTE legacy mapping members->trusted, trusted->helpers + try { + // helpers table from plot.getTrusted() + for (java.util.UUID uuid : plot.getTrusted()) { + com.plotsquared.core.persistence.entity.PlotMembershipEntity e = new com.plotsquared.core.persistence.entity.PlotMembershipEntity(); + e.setPlotId(plotId); + e.setUserUuid(uuid.toString()); + em.persist(e); + } + // trusted table from plot.getMembers() + for (java.util.UUID uuid : plot.getMembers()) { + com.plotsquared.core.persistence.entity.PlotTrustedEntity e = new com.plotsquared.core.persistence.entity.PlotTrustedEntity(); + e.setPlotId(plotId); + e.setUserUuid(uuid.toString()); + em.persist(e); + } + // denied table from plot.getDenied() + for (java.util.UUID uuid : plot.getDenied()) { + com.plotsquared.core.persistence.entity.PlotDeniedEntity e = new com.plotsquared.core.persistence.entity.PlotDeniedEntity(); + e.setPlotId(plotId); + e.setUserUuid(uuid.toString()); + em.persist(e); + } + } catch (Throwable t) { + LOGGER.warn("Failed to persist tiers for plot (x={}, z={}, world={})", plot.getId().getX(), plot.getId().getY(), world, t); + } + } + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed bulk create plots and data", e); + throw e; + } finally { + em.close(); + } + } + @Override public boolean swapPlots(final Plot plot1, final Plot plot2) { EntityManager em = emf.createEntityManager(); From 386a5eb057d8798e512891e2bf7d21606b946309 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Thu, 4 Sep 2025 19:30:55 +0200 Subject: [PATCH 041/141] feat: refactor plot creation methods to use PlotRepository for improved safety and consistency --- .../com/plotsquared/core/database/DBFunc.java | 28 +++---- .../repository/api/PlotRepository.java | 18 +++++ .../repository/jpa/PlotRepositoryJpa.java | 76 +++++++++++++++++++ 3 files changed, 103 insertions(+), 19 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java index 9273acb1f4..34020adbd9 100644 --- a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java +++ b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java @@ -147,10 +147,13 @@ public static void createPlotSafe( final Plot plot, final Runnable success, final Runnable failure ) { - if (dbManager == null) { - return; + PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + boolean created = repo.createPlotSafe(plot); + if (created) { + if (success != null) success.run(); + } else { + if (failure != null) failure.run(); } - DBFunc.dbManager.createPlotSafe(plot, success, failure); } /** @@ -159,22 +162,9 @@ public static void createPlotSafe( * @param plot Plot to create */ public static void createPlotAndSettings(Plot plot, Runnable whenDone) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.createPlotAndSettings(plot, whenDone); - } - - /** - * Create tables. - * - * @throws Exception - */ - public static void createTables() throws Exception { - if (dbManager == null) { - return; - } - DBFunc.dbManager.createTables(); + PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + repo.createPlotAndSettings(plot); + if (whenDone != null) whenDone.run(); } /** diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java index 3beb6f5690..e39a43ea3b 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java @@ -35,6 +35,24 @@ public interface PlotRepository { */ void createPlotsAndData(List plots); + /** + * Creates a plot if it does not already exist for the given world/x/z. + * Also creates an empty settings row. Mirrors legacy createPlotSafe behavior. + * Sets plot.temp to the generated id if created. + * + * @param plot plot to create + * @return true if a new plot was created; false if it already existed + */ + boolean createPlotSafe(Plot plot); + + /** + * Creates a plot and an empty settings row. Mirrors legacy createPlotAndSettings. + * Sets plot.temp to the generated id. + * + * @param plot plot to create + */ + void createPlotAndSettings(Plot plot); + /** * Finds a plot by its primary identifier. * diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java index 91349c1f6a..e65e0291bd 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java @@ -25,6 +25,82 @@ public PlotRepositoryJpa(EntityManagerFactory emf) { this.emf = emf; } + @Override + public boolean createPlotSafe(final Plot plot) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + String world = null; + try { world = plot.getWorldName(); } catch (Throwable ignored) {} + if (world == null) { world = plot.getArea().toString(); } + Optional existing = findByWorldAndId(world, plot.getId().getX(), plot.getId().getY()); + if (existing.isPresent()) { + tx.commit(); + return false; + } + PlotEntity pe = new PlotEntity(); + pe.setPlotIdX(plot.getId().getX()); + pe.setPlotIdZ(plot.getId().getY()); + UUID ownerUuid = null; + try { ownerUuid = plot.getOwnerAbs(); } catch (Throwable ignored) {} + pe.setOwner(ownerUuid != null ? ownerUuid.toString() : com.plotsquared.core.database.DBFunc.EVERYONE.toString()); + pe.setWorld(world); + em.persist(pe); + em.flush(); + if (pe.getId() != null) { + plot.temp = pe.getId().intValue(); + } + com.plotsquared.core.persistence.entity.PlotSettingsEntity se = new com.plotsquared.core.persistence.entity.PlotSettingsEntity(); + se.setPlot(pe); + se.setPosition("DEFAULT"); + em.persist(se); + tx.commit(); + return true; + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to create plot safely (plot={})", plot, e); + throw e; + } finally { + em.close(); + } + } + + @Override + public void createPlotAndSettings(final Plot plot) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + String world = null; + try { world = plot.getWorldName(); } catch (Throwable ignored) {} + if (world == null) { world = plot.getArea().toString(); } + PlotEntity pe = new PlotEntity(); + pe.setPlotIdX(plot.getId().getX()); + pe.setPlotIdZ(plot.getId().getY()); + UUID ownerUuid = null; + try { ownerUuid = plot.getOwnerAbs(); } catch (Throwable ignored) {} + pe.setOwner(ownerUuid != null ? ownerUuid.toString() : com.plotsquared.core.database.DBFunc.EVERYONE.toString()); + pe.setWorld(world); + em.persist(pe); + em.flush(); + if (pe.getId() != null) { + plot.temp = pe.getId().intValue(); + } + com.plotsquared.core.persistence.entity.PlotSettingsEntity se = new com.plotsquared.core.persistence.entity.PlotSettingsEntity(); + se.setPlot(pe); + se.setPosition("DEFAULT"); + em.persist(se); + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to create plot and settings (plot={})", plot, e); + throw e; + } finally { + em.close(); + } + } + @Override public void createPlotsAndData(final List plots) { if (plots == null || plots.isEmpty()) { From dedac79f379634bc5efe3e5a93c6928113283abd Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Thu, 4 Sep 2025 19:43:28 +0200 Subject: [PATCH 042/141] feat: refactor plot deletion methods to utilize PlotRepository for improved database management --- .../com/plotsquared/core/database/DBFunc.java | 10 ++- .../repository/api/PlotRepository.java | 15 ++++ .../repository/jpa/PlotRepositoryJpa.java | 79 +++++++++++++++++++ 3 files changed, 100 insertions(+), 4 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java index 34020adbd9..d837f927b8 100644 --- a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java +++ b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java @@ -173,10 +173,11 @@ public static void createPlotAndSettings(Plot plot, Runnable whenDone) { * @param plot Plot to delete */ public static void delete(Plot plot) { - if (plot.temp == -1 || dbManager == null) { + if (plot.temp == -1) { return; } - DBFunc.dbManager.delete(plot); + PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + repo.delete(plot); plot.temp = -1; } @@ -186,10 +187,11 @@ public static void delete(Plot plot) { * @param plot */ public static void deleteRatings(Plot plot) { - if (plot.temp == -1 || dbManager == null) { + if (plot.temp == -1) { return; } - DBFunc.dbManager.deleteRatings(plot); + PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + repo.deleteRatings(plot); } /** diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java index e39a43ea3b..e1b5a64f37 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java @@ -112,4 +112,19 @@ public interface PlotRepository { * @param id the plot id */ void deleteById(long id); + + /** + * Deletes all ratings for the given plot. + * + * @param plot the plot whose ratings should be removed + */ + void deleteRatings(Plot plot); + + /** + * Deletes the plot and all related data (flags, helpers, trusted, denied, ratings, and settings via cascade). + * No-op if the plot does not exist. + * + * @param plot the plot to delete + */ + void delete(Plot plot); } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java index e65e0291bd..5f2d5bb5ef 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java @@ -382,4 +382,83 @@ public void deleteById(long id) { em.close(); } } + + @Override + public void deleteRatings(final Plot plot) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + String world = null; + try { world = plot.getWorldName(); } catch (Throwable ignored) {} + if (world == null) { world = plot.getArea().toString(); } + PlotEntity pe = em.createNamedQuery("Plot.findByWorldAndId", PlotEntity.class) + .setParameter("world", world) + .setParameter("x", plot.getId().getX()) + .setParameter("z", plot.getId().getY()) + .getResultStream().findFirst().orElse(null); + if (pe != null && pe.getId() != null) { + em.createQuery("DELETE FROM PlotRatingEntity r WHERE r.plotId = :plotId") + .setParameter("plotId", pe.getId()) + .executeUpdate(); + } + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to delete ratings for plot (plot={})", plot, e); + throw e; + } finally { + em.close(); + } + } + + @Override + public void delete(final Plot plot) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + String world = null; + try { world = plot.getWorldName(); } catch (Throwable ignored) {} + if (world == null) { world = plot.getArea().toString(); } + PlotEntity pe = em.createNamedQuery("Plot.findByWorldAndId", PlotEntity.class) + .setParameter("world", world) + .setParameter("x", plot.getId().getX()) + .setParameter("z", plot.getId().getY()) + .getResultStream().findFirst().orElse(null); + if (pe != null && pe.getId() != null) { + Long plotId = pe.getId(); + // Delete children first to satisfy FK constraints + em.createQuery("DELETE FROM PlotFlagEntity f WHERE f.plot.id = :plotId") + .setParameter("plotId", plotId) + .executeUpdate(); + em.createQuery("DELETE FROM PlotMembershipEntity e WHERE e.plotId = :plotId") + .setParameter("plotId", plotId) + .executeUpdate(); + em.createQuery("DELETE FROM PlotTrustedEntity e WHERE e.plotId = :plotId") + .setParameter("plotId", plotId) + .executeUpdate(); + em.createQuery("DELETE FROM PlotDeniedEntity e WHERE e.plotId = :plotId") + .setParameter("plotId", plotId) + .executeUpdate(); + em.createQuery("DELETE FROM PlotRatingEntity r WHERE r.plotId = :plotId") + .setParameter("plotId", plotId) + .executeUpdate(); + // Remove settings explicitly to mirror legacy behavior and avoid orphan rows + em.createQuery("DELETE FROM PlotSettingsEntity s WHERE s.id = :plotId") + .setParameter("plotId", plotId) + .executeUpdate(); + // Remove plot + PlotEntity managed = em.contains(pe) ? pe : em.merge(pe); + em.remove(managed); + } + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to delete plot (plot={})", plot, e); + throw e; + } finally { + em.close(); + } + } } From b5d5af232afa6132f87d557ce127dd52a9f454d1 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Thu, 4 Sep 2025 20:32:14 +0200 Subject: [PATCH 043/141] feat: remove unused UUID service imports and related code for cleaner architecture --- .../plotsquared/bukkit/BukkitPlatform.java | 122 --------------- .../bukkit/uuid/EssentialsUUIDService.java | 66 -------- .../bukkit/uuid/LuckPermsUUIDService.java | 81 ---------- .../bukkit/uuid/OfflinePlayerUUIDService.java | 81 ---------- .../bukkit/uuid/PaperUUIDService.java | 60 -------- .../bukkit/uuid/SQLiteUUIDService.java | 143 ------------------ .../bukkit/uuid/SquirrelIdUUIDService.java | 112 -------------- .../com/plotsquared/core/PlotSquared.java | 11 -- 8 files changed, 676 deletions(-) delete mode 100644 Bukkit/src/main/java/com/plotsquared/bukkit/uuid/EssentialsUUIDService.java delete mode 100644 Bukkit/src/main/java/com/plotsquared/bukkit/uuid/LuckPermsUUIDService.java delete mode 100644 Bukkit/src/main/java/com/plotsquared/bukkit/uuid/OfflinePlayerUUIDService.java delete mode 100644 Bukkit/src/main/java/com/plotsquared/bukkit/uuid/PaperUUIDService.java delete mode 100644 Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SQLiteUUIDService.java delete mode 100644 Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SquirrelIdUUIDService.java diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java index e0dbb081ed..4570989e32 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java @@ -54,12 +54,6 @@ import com.plotsquared.bukkit.util.task.BukkitTaskManager; import com.plotsquared.bukkit.util.task.PaperTimeConverter; import com.plotsquared.bukkit.util.task.SpigotTimeConverter; -import com.plotsquared.bukkit.uuid.EssentialsUUIDService; -import com.plotsquared.bukkit.uuid.LuckPermsUUIDService; -import com.plotsquared.bukkit.uuid.OfflinePlayerUUIDService; -import com.plotsquared.bukkit.uuid.PaperUUIDService; -import com.plotsquared.bukkit.uuid.SQLiteUUIDService; -import com.plotsquared.bukkit.uuid.SquirrelIdUUIDService; import com.plotsquared.core.PlotPlatform; import com.plotsquared.core.PlotSquared; import com.plotsquared.core.backup.BackupManager; @@ -71,15 +65,12 @@ import com.plotsquared.core.configuration.Storage; import com.plotsquared.core.configuration.caption.ChatFormatter; import com.plotsquared.core.configuration.file.YamlConfiguration; -import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.events.RemoveRoadEntityEvent; import com.plotsquared.core.events.Result; import com.plotsquared.core.generator.GeneratorWrapper; import com.plotsquared.core.generator.IndependentPlotGenerator; import com.plotsquared.core.generator.SingleWorldGenerator; -import com.plotsquared.core.inject.annotations.BackgroundPipeline; import com.plotsquared.core.inject.annotations.DefaultGenerator; -import com.plotsquared.core.inject.annotations.ImpromptuPipeline; import com.plotsquared.core.inject.annotations.WorldConfig; import com.plotsquared.core.inject.annotations.WorldFile; import com.plotsquared.core.inject.modules.PlotSquaredModule; @@ -100,7 +91,6 @@ import com.plotsquared.core.setup.PlotAreaBuilder; import com.plotsquared.core.setup.SettingsNodesWrapper; import com.plotsquared.core.util.EventDispatcher; -import com.plotsquared.core.util.FileUtils; import com.plotsquared.core.util.PlatformWorldManager; import com.plotsquared.core.util.PlayerManager; import com.plotsquared.core.util.PremiumVerification; @@ -110,8 +100,6 @@ import com.plotsquared.core.util.task.TaskManager; import com.plotsquared.core.util.task.TaskTime; import com.plotsquared.core.uuid.CacheUUIDService; -import com.plotsquared.core.uuid.UUIDPipeline; -import com.plotsquared.core.uuid.offline.OfflineModeUUIDService; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.bukkit.BukkitAdapter; import io.papermc.lib.PaperLib; @@ -209,12 +197,6 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl @Inject private BackupManager backupManager; @Inject - @ImpromptuPipeline - private UUIDPipeline impromptuPipeline; - @Inject - @BackgroundPipeline - private UUIDPipeline backgroundPipeline; - @Inject private PlatformWorldManager worldManager; private Locale serverLocale; @@ -433,108 +415,6 @@ public void onEnable() { // Once the server has loaded force updating all generators known to PlotSquared TaskManager.runTaskLater(() -> PlotSquared.platform().setupUtils().updateGenerators(true), TaskTime.ticks(1L)); - // Services are accessed in order - final CacheUUIDService cacheUUIDService = new CacheUUIDService(Settings.UUID.UUID_CACHE_SIZE); - this.impromptuPipeline.registerService(cacheUUIDService); - this.backgroundPipeline.registerService(cacheUUIDService); - this.impromptuPipeline.registerConsumer(cacheUUIDService); - this.backgroundPipeline.registerConsumer(cacheUUIDService); - - // Now, if the server is in offline mode we can only use profiles and direct UUID - // access, and so we skip the player profile stuff as well as SquirrelID (Mojang lookups) - if (Settings.UUID.OFFLINE) { - final OfflineModeUUIDService offlineModeUUIDService = new OfflineModeUUIDService(); - this.impromptuPipeline.registerService(offlineModeUUIDService); - this.backgroundPipeline.registerService(offlineModeUUIDService); - LOGGER.info("(UUID) Using the offline mode UUID service"); - } - - if (Settings.UUID.SERVICE_BUKKIT) { - final OfflinePlayerUUIDService offlinePlayerUUIDService = new OfflinePlayerUUIDService(); - this.impromptuPipeline.registerService(offlinePlayerUUIDService); - this.backgroundPipeline.registerService(offlinePlayerUUIDService); - } - - final SQLiteUUIDService sqLiteUUIDService = new SQLiteUUIDService("user_cache.db"); - - final SQLiteUUIDService legacyUUIDService; - if (Settings.UUID.LEGACY_DATABASE_SUPPORT && FileUtils - .getFile(PlotSquared.platform().getDirectory(), "usercache.db") - .exists()) { - legacyUUIDService = new SQLiteUUIDService("usercache.db"); - } else { - legacyUUIDService = null; - } - - final LuckPermsUUIDService luckPermsUUIDService; - if (Settings.UUID.SERVICE_LUCKPERMS && Bukkit.getPluginManager().getPlugin("LuckPerms") != null) { - luckPermsUUIDService = new LuckPermsUUIDService(); - LOGGER.info("(UUID) Using LuckPerms as a complementary UUID service"); - } else { - luckPermsUUIDService = null; - } - - final EssentialsUUIDService essentialsUUIDService; - if (Settings.UUID.SERVICE_ESSENTIALSX && Bukkit.getPluginManager().getPlugin("Essentials") != null) { - essentialsUUIDService = new EssentialsUUIDService(); - LOGGER.info("(UUID) Using EssentialsX as a complementary UUID service"); - } else { - essentialsUUIDService = null; - } - - if (!Settings.UUID.OFFLINE) { - // If running Paper we'll also try to use their profiles - if (Bukkit.getOnlineMode() && PaperLib.isPaper() && Settings.UUID.SERVICE_PAPER) { - final PaperUUIDService paperUUIDService = new PaperUUIDService(); - this.impromptuPipeline.registerService(paperUUIDService); - this.backgroundPipeline.registerService(paperUUIDService); - LOGGER.info("(UUID) Using Paper as a complementary UUID service"); - } - - this.impromptuPipeline.registerService(sqLiteUUIDService); - this.backgroundPipeline.registerService(sqLiteUUIDService); - this.impromptuPipeline.registerConsumer(sqLiteUUIDService); - this.backgroundPipeline.registerConsumer(sqLiteUUIDService); - - if (legacyUUIDService != null) { - this.impromptuPipeline.registerService(legacyUUIDService); - this.backgroundPipeline.registerService(legacyUUIDService); - } - - // Plugin providers - if (luckPermsUUIDService != null) { - this.impromptuPipeline.registerService(luckPermsUUIDService); - this.backgroundPipeline.registerService(luckPermsUUIDService); - } - if (essentialsUUIDService != null) { - this.impromptuPipeline.registerService(essentialsUUIDService); - this.backgroundPipeline.registerService(essentialsUUIDService); - } - - if (Settings.UUID.IMPROMPTU_SERVICE_MOJANG_API) { - final SquirrelIdUUIDService impromptuMojangService = new SquirrelIdUUIDService(Settings.UUID.IMPROMPTU_LIMIT); - this.impromptuPipeline.registerService(impromptuMojangService); - } - final SquirrelIdUUIDService backgroundMojangService = new SquirrelIdUUIDService(Settings.UUID.BACKGROUND_LIMIT); - this.backgroundPipeline.registerService(backgroundMojangService); - } else { - this.impromptuPipeline.registerService(sqLiteUUIDService); - this.backgroundPipeline.registerService(sqLiteUUIDService); - this.impromptuPipeline.registerConsumer(sqLiteUUIDService); - this.backgroundPipeline.registerConsumer(sqLiteUUIDService); - - if (legacyUUIDService != null) { - this.impromptuPipeline.registerService(legacyUUIDService); - this.backgroundPipeline.registerService(legacyUUIDService); - } - } - - this.impromptuPipeline.storeImmediately("*", DBFunc.EVERYONE); - - if (Settings.UUID.BACKGROUND_CACHING_ENABLED) { - this.startUuidCaching(sqLiteUUIDService, cacheUUIDService); - } - if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) { injector.getInstance(PAPIPlaceholders.class).register(); if (Settings.Enabled_Components.EXTERNAL_PLACEHOLDERS) { @@ -658,7 +538,6 @@ private void unload() { } private void startUuidCaching( - final @NonNull SQLiteUUIDService sqLiteUUIDService, final @NonNull CacheUUIDService cacheUUIDService ) { // Record all unique UUID's and put them into a queue @@ -675,7 +554,6 @@ private void startUuidCaching( Executors.newSingleThreadScheduledExecutor().schedule(() -> { // Begin by reading all the SQLite cache at once - cacheUUIDService.accept(sqLiteUUIDService.getAll()); // Now fetch names for all known UUIDs final int totalSize = uuidQueue.size(); int read = 0; diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/EssentialsUUIDService.java b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/EssentialsUUIDService.java deleted file mode 100644 index e87b8487bc..0000000000 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/EssentialsUUIDService.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.bukkit.uuid; - -import com.earth2me.essentials.Essentials; -import com.earth2me.essentials.User; -import com.plotsquared.core.uuid.UUIDMapping; -import com.plotsquared.core.uuid.UUIDService; -import org.checkerframework.checker.nullness.qual.NonNull; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.UUID; - -/** - * UUID service using the EssentialsX API - */ -public class EssentialsUUIDService implements UUIDService { - - private final Essentials essentials; - - public EssentialsUUIDService() { - this.essentials = Essentials.getPlugin(Essentials.class); - } - - @Override - public @NonNull List getNames(final @NonNull List uuids) { - return Collections.emptyList(); - } - - @Override - public @NonNull List getUUIDs(final @NonNull List usernames) { - final List mappings = new ArrayList<>(usernames.size()); - for (final String username : usernames) { - try { - final User user = essentials.getUser(username); - if (user != null) { - final UUID uuid = user.getConfigUUID(); - if (uuid != null) { - mappings.add(new UUIDMapping(uuid, username)); - } - } - } catch (final Exception ignored) { - } - } - return mappings; - } - -} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/LuckPermsUUIDService.java b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/LuckPermsUUIDService.java deleted file mode 100644 index 20e26b53e9..0000000000 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/LuckPermsUUIDService.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.bukkit.uuid; - -import com.plotsquared.core.uuid.UUIDMapping; -import com.plotsquared.core.uuid.UUIDService; -import net.luckperms.api.LuckPerms; -import net.luckperms.api.model.user.UserManager; -import org.bukkit.Bukkit; -import org.bukkit.plugin.RegisteredServiceProvider; -import org.checkerframework.checker.nullness.qual.NonNull; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -/** - * UUID service that uses the LuckPerms API - */ -public class LuckPermsUUIDService implements UUIDService { - - private final LuckPerms luckPerms; - - public LuckPermsUUIDService() { - final RegisteredServiceProvider provider = Bukkit.getServicesManager().getRegistration(LuckPerms.class); - if (provider != null) { - this.luckPerms = provider.getProvider(); - } else { - throw new IllegalStateException("LuckPerms not available"); - } - } - - @Override - public @NonNull List getNames(final @NonNull List uuids) { - final List mappings = new ArrayList<>(uuids.size()); - final UserManager userManager = this.luckPerms.getUserManager(); - for (final UUID uuid : uuids) { - try { - final String username = userManager.lookupUsername(uuid).get(); - if (username != null) { - mappings.add(new UUIDMapping(uuid, username)); - } - } catch (final Exception ignored) { - } - } - return mappings; - } - - @Override - public @NonNull List getUUIDs(final @NonNull List usernames) { - final List mappings = new ArrayList<>(usernames.size()); - final UserManager userManager = this.luckPerms.getUserManager(); - for (final String username : usernames) { - try { - final UUID uuid = userManager.lookupUniqueId(username).get(); - if (username != null) { - mappings.add(new UUIDMapping(uuid, username)); - } - } catch (final Exception ignored) { - } - } - return mappings; - } - -} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/OfflinePlayerUUIDService.java b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/OfflinePlayerUUIDService.java deleted file mode 100644 index 4c48c016d7..0000000000 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/OfflinePlayerUUIDService.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.bukkit.uuid; - -import com.google.common.base.Charsets; -import com.plotsquared.core.configuration.Settings; -import com.plotsquared.core.uuid.UUIDMapping; -import com.plotsquared.core.uuid.UUIDService; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.checkerframework.checker.nullness.qual.NonNull; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.UUID; - -/** - * UUID service that use {@link org.bukkit.OfflinePlayer offline players} - */ -public class OfflinePlayerUUIDService implements UUIDService { - - @Override - public @NonNull List getNames(final @NonNull List uuids) { - if (Settings.UUID.FORCE_LOWERCASE || Bukkit.getWorlds().isEmpty()) { - return Collections.emptyList(); // This is useless now - } - final List wrappers = new ArrayList<>(uuids.size()); - for (final UUID uuid : uuids) { - final OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(uuid); - try { - if (offlinePlayer.hasPlayedBefore()) { - wrappers.add(new UUIDMapping(uuid, offlinePlayer.getName())); - } - } catch (final Exception ignored) { - } /* This can be safely ignored. If this happens, it is - probably because it's called before the worlds have - been loaded. This is bad, but does not break anything */ - } - return wrappers; - } - - @Override - public @NonNull List getUUIDs(final @NonNull List usernames) { - final List wrappers = new ArrayList<>(usernames.size()); - for (final String username : usernames) { - if (Settings.UUID.OFFLINE) { - if (Settings.UUID.FORCE_LOWERCASE) { - wrappers.add(new UUIDMapping(UUID.nameUUIDFromBytes(("OfflinePlayer:" + - username.toLowerCase()).getBytes(Charsets.UTF_8)), username)); - } else { - wrappers.add(new UUIDMapping(UUID.nameUUIDFromBytes(("OfflinePlayer:" + - username).getBytes(Charsets.UTF_8)), username)); - } - } else { - final OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(username); - if (offlinePlayer.hasPlayedBefore()) { - wrappers.add(new UUIDMapping(offlinePlayer.getUniqueId(), offlinePlayer.getName())); - } - } - } - return wrappers; - } - -} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/PaperUUIDService.java b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/PaperUUIDService.java deleted file mode 100644 index 296cb47c51..0000000000 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/PaperUUIDService.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.bukkit.uuid; - -import com.destroystokyo.paper.profile.PlayerProfile; -import com.plotsquared.core.uuid.UUIDMapping; -import com.plotsquared.core.uuid.UUIDService; -import org.bukkit.Bukkit; -import org.checkerframework.checker.nullness.qual.NonNull; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -/** - * UUID service that uses the Paper profile API - */ -public class PaperUUIDService implements UUIDService { - - @Override - public @NonNull List getNames(final @NonNull List uuids) { - final List mappings = new ArrayList<>(uuids.size()); - for (final UUID uuid : uuids) { - final PlayerProfile playerProfile = Bukkit.createProfile(uuid); - if ((playerProfile.isComplete() || playerProfile.completeFromCache()) && playerProfile.getId() != null) { - mappings.add(new UUIDMapping(playerProfile.getId(), playerProfile.getName())); - } - } - return mappings; - } - - @Override - public @NonNull List getUUIDs(final @NonNull List usernames) { - final List mappings = new ArrayList<>(usernames.size()); - for (final String username : usernames) { - final PlayerProfile playerProfile = Bukkit.createProfile(username); - if ((playerProfile.isComplete() || playerProfile.completeFromCache()) && playerProfile.getId() != null) { - mappings.add(new UUIDMapping(playerProfile.getId(), playerProfile.getName())); - } - } - return mappings; - } - -} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SQLiteUUIDService.java b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SQLiteUUIDService.java deleted file mode 100644 index 9193b4f0a0..0000000000 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SQLiteUUIDService.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.bukkit.uuid; - -import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.database.SQLite; -import com.plotsquared.core.util.FileUtils; -import com.plotsquared.core.uuid.UUIDMapping; -import com.plotsquared.core.uuid.UUIDService; -import org.checkerframework.checker.nullness.qual.NonNull; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.UUID; -import java.util.function.Consumer; - -/** - * UUID service that uses the (legacy) SQL UUID cache - */ -public class SQLiteUUIDService implements UUIDService, Consumer> { - - private final SQLite sqlite; - - public SQLiteUUIDService(final String fileName) { - this.sqlite = - new SQLite(FileUtils.getFile(PlotSquared.platform().getDirectory(), fileName)); - try { - this.sqlite.openConnection(); - } catch (ClassNotFoundException | SQLException e) { - e.printStackTrace(); - } - - try (PreparedStatement stmt = getConnection().prepareStatement( - "CREATE TABLE IF NOT EXISTS `usercache` (uuid VARCHAR(32) NOT NULL, username VARCHAR(32) NOT NULL, PRIMARY KEY (uuid))")) { - stmt.execute(); - } catch (SQLException e) { - e.printStackTrace(); - } - } - - private Connection getConnection() { - synchronized (this.sqlite) { - return this.sqlite.getConnection(); - } - } - - @Override - public @NonNull List getNames(final @NonNull List uuids) { - final List mappings = new ArrayList<>(uuids.size()); - try (final PreparedStatement statement = getConnection() - .prepareStatement("SELECT `username` FROM `usercache` WHERE `uuid` = ?")) { - for (final UUID uuid : uuids) { - statement.setString(1, uuid.toString()); - try (final ResultSet resultSet = statement.executeQuery()) { - if (resultSet.next()) { - mappings.add(new UUIDMapping(uuid, resultSet.getString("username"))); - } - } - } - } catch (final Exception e) { - e.printStackTrace(); - } - return mappings; - } - - @Override - public @NonNull List getUUIDs(@NonNull List usernames) { - final List mappings = new ArrayList<>(usernames.size()); - try (final PreparedStatement statement = getConnection() - .prepareStatement("SELECT `uuid` FROM `usercache` WHERE `username` = ?")) { - for (final String username : usernames) { - statement.setString(1, username); - try (final ResultSet resultSet = statement.executeQuery()) { - if (resultSet.next()) { - mappings.add(new UUIDMapping( - UUID.fromString(resultSet.getString("uuid")), - username - )); - } - } - } - } catch (final Exception e) { - e.printStackTrace(); - } - return mappings; - } - - @Override - public void accept(final List uuidWrappers) { - try (final PreparedStatement statement = getConnection() - .prepareStatement("INSERT OR REPLACE INTO `usercache` (`uuid`, `username`) VALUES(?, ?)")) { - for (final UUIDMapping mapping : uuidWrappers) { - statement.setString(1, mapping.uuid().toString()); - statement.setString(2, mapping.username()); - statement.executeUpdate(); - } - } catch (SQLException e) { - e.printStackTrace(); - } - } - - /** - * Read the entire cache at once - * - * @return All read mappings - */ - public @NonNull List getAll() { - final List mappings = new LinkedList<>(); - try (final PreparedStatement statement = getConnection().prepareStatement("SELECT * FROM `usercache`")) { - try (final ResultSet resultSet = statement.executeQuery()) { - while (resultSet.next()) { - mappings.add(new UUIDMapping(UUID.fromString(resultSet.getString("uuid")), resultSet.getString("username"))); - } - } - } catch (final Exception e) { - e.printStackTrace(); - } - return mappings; - } - - -} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SquirrelIdUUIDService.java b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SquirrelIdUUIDService.java deleted file mode 100644 index 58bda3e3ab..0000000000 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SquirrelIdUUIDService.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.bukkit.uuid; - -import com.google.common.util.concurrent.RateLimiter; -import com.plotsquared.core.configuration.Settings; -import com.plotsquared.core.uuid.UUIDMapping; -import com.plotsquared.core.uuid.UUIDService; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.enginehub.squirrelid.Profile; -import org.enginehub.squirrelid.resolver.HttpRepositoryService; -import org.enginehub.squirrelid.resolver.ProfileService; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.UUID; - -/** - * UUID service using SquirrelID - */ -@SuppressWarnings("UnstableApiUsage") -public class SquirrelIdUUIDService implements UUIDService { - - private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + SquirrelIdUUIDService.class.getSimpleName()); - - private final ProfileService profileService; - private final RateLimiter rateLimiter; - - /** - * Create a new SquirrelID UUID service - * - * @param rateLimit Mojangs rate limit is 600 requests per 10 minutes. - * This parameter specifies how many of those requests - * we can use before our internal rate limit kicks in. - */ - public SquirrelIdUUIDService(final int rateLimit) { - this.profileService = HttpRepositoryService.forMinecraft(); - // RateLimiter uses request per seconds. The constructor - // parameter rateLimit is requests per 600 seconds - this.rateLimiter = RateLimiter.create(rateLimit / 600.0D); - } - - @Override - public @NonNull List getNames(final @NonNull List uuids) { - final List results = new ArrayList<>(uuids.size()); - this.rateLimiter.acquire(uuids.size()); - try { - try { - for (final Profile profile : this.profileService.findAllByUuid(uuids)) { - results.add(new UUIDMapping(profile.getUniqueId(), profile.getName())); - } - } catch (final IllegalArgumentException illegalArgumentException) { - // - // This means that the UUID was invalid for whatever reason, we'll try to - // go through them one by one - // - if (uuids.size() >= 2) { - if (Settings.DEBUG) { - LOGGER.info("(UUID) Found invalid UUID in batch. Will try each UUID individually."); - } - for (final UUID uuid : uuids) { - final List result = this.getNames(Collections.singletonList(uuid)); - if (result.isEmpty()) { - continue; - } - results.add(result.get(0)); - } - } else if (uuids.size() == 1 && Settings.DEBUG) { - LOGGER.info("(UUID) Found invalid UUID: {}", uuids.get(0)); - } - } - } catch (IOException | InterruptedException e) { - e.printStackTrace(); - } - return results; - } - - @Override - public @NonNull List getUUIDs(final @NonNull List usernames) { - final List results = new ArrayList<>(usernames.size()); - this.rateLimiter.acquire(usernames.size()); - try { - for (final Profile profile : this.profileService.findAllByName(usernames)) { - results.add(new UUIDMapping(profile.getUniqueId(), profile.getName())); - } - } catch (IOException | InterruptedException e) { - e.printStackTrace(); - } - return results; - } - -} diff --git a/Core/src/main/java/com/plotsquared/core/PlotSquared.java b/Core/src/main/java/com/plotsquared/core/PlotSquared.java index 324631c23e..50db209dcb 100644 --- a/Core/src/main/java/com/plotsquared/core/PlotSquared.java +++ b/Core/src/main/java/com/plotsquared/core/PlotSquared.java @@ -31,10 +31,6 @@ import com.plotsquared.core.configuration.file.YamlConfiguration; import com.plotsquared.core.configuration.serialization.ConfigurationSerialization; import com.plotsquared.core.database.DBFunc; -import com.plotsquared.core.database.Database; -import com.plotsquared.core.database.MySQL; -import com.plotsquared.core.database.SQLManager; -import com.plotsquared.core.database.SQLite; import com.plotsquared.core.generator.GeneratorWrapper; import com.plotsquared.core.generator.HybridPlotWorld; import com.plotsquared.core.generator.HybridUtils; @@ -1227,13 +1223,6 @@ public void disable() { try { eventDispatcher.unregisterAll(); checkRoadRegenPersistence(); - // Validate that all data in the db is correct - final HashSet plots = new HashSet<>(); - try { - forEachPlotRaw(plots::add); - } catch (final Exception ignored) { - } - DBFunc.validatePlots(plots); } catch (NullPointerException throwable) { LOGGER.error("Could not close database connection", throwable); throwable.printStackTrace(); From e1a0af0594a9132d2838fd9bd60717826b75ea5a Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Thu, 4 Sep 2025 20:34:15 +0200 Subject: [PATCH 044/141] feat: remove DatabaseCommand from command list for cleaner command management --- .../core/command/DatabaseCommand.java | 275 ------------------ .../plotsquared/core/command/MainCommand.java | 1 - 2 files changed, 276 deletions(-) delete mode 100644 Core/src/main/java/com/plotsquared/core/command/DatabaseCommand.java diff --git a/Core/src/main/java/com/plotsquared/core/command/DatabaseCommand.java b/Core/src/main/java/com/plotsquared/core/command/DatabaseCommand.java deleted file mode 100644 index 5d24194c0d..0000000000 --- a/Core/src/main/java/com/plotsquared/core/command/DatabaseCommand.java +++ /dev/null @@ -1,275 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.core.command; - -import com.google.inject.Inject; -import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.configuration.caption.StaticCaption; -import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.configuration.file.YamlConfiguration; -import com.plotsquared.core.database.DBFunc; -import com.plotsquared.core.database.Database; -import com.plotsquared.core.database.MySQL; -import com.plotsquared.core.database.SQLManager; -import com.plotsquared.core.database.SQLite; -import com.plotsquared.core.inject.annotations.WorldConfig; -import com.plotsquared.core.listener.PlotListener; -import com.plotsquared.core.player.PlotPlayer; -import com.plotsquared.core.plot.Plot; -import com.plotsquared.core.plot.PlotArea; -import com.plotsquared.core.plot.PlotId; -import com.plotsquared.core.plot.world.PlotAreaManager; -import com.plotsquared.core.plot.world.SinglePlotArea; -import com.plotsquared.core.util.EventDispatcher; -import com.plotsquared.core.util.FileUtils; -import com.plotsquared.core.util.query.PlotQuery; -import com.plotsquared.core.util.task.TaskManager; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.minimessage.tag.Tag; -import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; -import org.checkerframework.checker.nullness.qual.NonNull; - -import java.io.File; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map.Entry; - -@CommandDeclaration(command = "database", - aliases = {"convert"}, - category = CommandCategory.ADMINISTRATION, - permission = "plots.database", - requiredType = RequiredType.CONSOLE, - usage = "/plot database [area] ") -public class DatabaseCommand extends SubCommand { - - private final PlotAreaManager plotAreaManager; - private final EventDispatcher eventDispatcher; - private final PlotListener plotListener; - private final YamlConfiguration worldConfiguration; - - @Inject - public DatabaseCommand( - final @NonNull PlotAreaManager plotAreaManager, - final @NonNull EventDispatcher eventDispatcher, - final @NonNull PlotListener plotListener, - @WorldConfig final @NonNull YamlConfiguration worldConfiguration - ) { - this.plotAreaManager = plotAreaManager; - this.eventDispatcher = eventDispatcher; - this.plotListener = plotListener; - this.worldConfiguration = worldConfiguration; - } - - public static void insertPlots( - final SQLManager manager, final List plots, - final PlotPlayer player - ) { - TaskManager.runTaskAsync(() -> { - try { - ArrayList ps = new ArrayList<>(plots); - player.sendMessage(TranslatableCaption.of("database.starting_conversion")); - manager.createPlotsAndData(ps, () -> { - player.sendMessage(TranslatableCaption.of("database.conversion_done")); - manager.close(); - }); - } catch (Exception e) { - player.sendMessage(TranslatableCaption.of("database.conversion_failed")); - e.printStackTrace(); - } - }); - } - - @Override - public boolean onCommand(final PlotPlayer player, String[] args) { - if (args.length < 1) { - player.sendMessage( - TranslatableCaption.of("commandconfig.command_syntax"), - TagResolver.resolver( - "value", - Tag.inserting(Component.text("/plot database [area] ")) - ) - ); - return false; - } - List plots; - PlotArea area = this.plotAreaManager.getPlotAreaByString(args[0]); - if (area != null) { - plots = PlotSquared.get().sortPlotsByTemp(area.getPlots()); - args = Arrays.copyOfRange(args, 1, args.length); - } else { - plots = PlotSquared.get().sortPlotsByTemp(PlotQuery.newQuery().allPlots().asList()); - } - if (args.length < 1) { - player.sendMessage( - TranslatableCaption.of("commandconfig.command_syntax"), - TagResolver.resolver("value", Tag.inserting(Component.text("/plot database [area] "))) - ); - player.sendMessage(TranslatableCaption.of("database.arg")); - return false; - } - try { - Database implementation; - String prefix = ""; - switch (args[0].toLowerCase()) { - case "import" -> { - if (args.length < 2) { - player.sendMessage( - TranslatableCaption.of("commandconfig.command_syntax"), - TagResolver.resolver( - "value", - Tag.inserting(Component.text("/plot database import [prefix]")) - ) - ); - return false; - } - File file = FileUtils.getFile( - PlotSquared.platform().getDirectory(), - args[1].endsWith(".db") ? args[1] : args[1] + ".db" - ); - if (!file.exists()) { - player.sendMessage( - TranslatableCaption.of("database.does_not_exist"), - TagResolver.resolver("value", Tag.inserting(Component.text(file.toString()))) - ); - return false; - } - player.sendMessage(TranslatableCaption.of("database.starting_conversion")); - implementation = new SQLite(file); - SQLManager manager = new SQLManager(implementation, args.length == 3 ? args[2] : "", - this.eventDispatcher, this.plotListener, this.worldConfiguration - ); - HashMap> map = manager.getPlots(); - plots = new ArrayList<>(); - for (Entry> entry : map.entrySet()) { - String areaName = entry.getKey(); - PlotArea pa = this.plotAreaManager.getPlotAreaByString(areaName); - if (pa != null) { - for (Entry entry2 : entry.getValue().entrySet()) { - Plot plot = entry2.getValue(); - if (pa.getOwnedPlotAbs(plot.getId()) != null) { - if (pa instanceof SinglePlotArea) { - Plot newPlot = pa.getNextFreePlot(null, plot.getId()); - if (newPlot != null) { - PlotId newId = newPlot.getId(); - PlotId id = plot.getId(); - File worldFile = - new File( - PlotSquared.platform().worldContainer(), - id.toCommaSeparatedString() - ); - if (worldFile.exists()) { - File newFile = - new File( - PlotSquared.platform().worldContainer(), - newId.toCommaSeparatedString() - ); - worldFile.renameTo(newFile); - } - plot.setId(newId); - plot.setArea(pa); - plots.add(plot); - continue; - } - } - player.sendMessage( - TranslatableCaption.of("database.skipping_duplicated_plot"), - TagResolver.builder() - .tag("plot", Tag.inserting(Component.text(plot.toString()))) - .tag("id", Tag.inserting(Component.text(plot.temp))) - .build() - ); - continue; - } - plot.setArea(pa); - plots.add(plot); - } - } else { - HashMap plotMap = PlotSquared.get().plots_tmp - .computeIfAbsent(areaName, k -> new HashMap<>()); - plotMap.putAll(entry.getValue()); - } - } - DBFunc.createPlotsAndData( - plots, - () -> player.sendMessage(TranslatableCaption.of("database.conversion_done")) - ); - return true; - } - case "mysql" -> { - if (args.length < 6) { - player.sendMessage(StaticCaption.of( - "/plot database mysql [host] [port] [username] [password] [database] {prefix}")); - return false; - } - String host = args[1]; - String port = args[2]; - String username = args[3]; - String password = args[4]; - String database = args[5]; - if (args.length > 6) { - prefix = args[6]; - } - implementation = new MySQL(host, port, database, username, password); - } - case "sqlite" -> { - if (args.length < 2) { - player.sendMessage(StaticCaption.of("/plot database sqlite [file]")); - return false; - } - File sqliteFile = - FileUtils.getFile(PlotSquared.platform().getDirectory(), args[1] + ".db"); - implementation = new SQLite(sqliteFile); - } - default -> { - player.sendMessage(StaticCaption.of("/plot database [sqlite/mysql]")); - return false; - } - } - try { - SQLManager manager = new SQLManager( - implementation, - prefix, - this.eventDispatcher, - this.plotListener, - this.worldConfiguration - ); - DatabaseCommand.insertPlots(manager, plots, player); - return true; - } catch (ClassNotFoundException | SQLException e) { - player.sendMessage(TranslatableCaption.of("database.failed_to_save_plots")); - player.sendMessage(TranslatableCaption.of("errors.stacktrace_begin")); - e.printStackTrace(); - player.sendMessage(TranslatableCaption.of("errors.stacktrace_end")); - player.sendMessage(TranslatableCaption.of("database.invalid_args")); - return false; - } - } catch (ClassNotFoundException | SQLException e) { - player.sendMessage(TranslatableCaption.of("database.failed_to_open")); - player.sendMessage(TranslatableCaption.of("errors.stacktrace_begin")); - e.printStackTrace(); - player.sendMessage(TranslatableCaption.of("errors.stacktrace_end")); - player.sendMessage(TranslatableCaption.of("database.invalid_args")); - return false; - } - } - -} diff --git a/Core/src/main/java/com/plotsquared/core/command/MainCommand.java b/Core/src/main/java/com/plotsquared/core/command/MainCommand.java index 5ceafa6011..7c45b96c67 100644 --- a/Core/src/main/java/com/plotsquared/core/command/MainCommand.java +++ b/Core/src/main/java/com/plotsquared/core/command/MainCommand.java @@ -117,7 +117,6 @@ public static MainCommand getInstance() { commands.add(Kick.class); commands.add(Inbox.class); commands.add(Comment.class); - commands.add(DatabaseCommand.class); commands.add(Swap.class); commands.add(Music.class); commands.add(DebugRoadRegen.class); From f84e8490e3936d99c692bb2c199073dd4102c1ad Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Thu, 4 Sep 2025 21:50:22 +0200 Subject: [PATCH 045/141] feat: add cluster and plot repository methods for bulk world updates and settings management --- .../repository/api/ClusterRepository.java | 25 +++++++++++ .../api/ClusterSettingsRepository.java | 26 ++++++++++++ .../repository/api/PlotDeniedRepository.java | 7 ++++ .../api/PlotMembershipRepository.java | 7 ++++ .../repository/api/PlotRepository.java | 42 +++++++++++++++++++ .../api/PlotSettingsRepository.java | 20 +++++++++ .../repository/api/PlotTrustedRepository.java | 7 ++++ 7 files changed, 134 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterSettingsRepository.java diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterRepository.java index 821fb81307..3ec5d93160 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterRepository.java @@ -37,6 +37,11 @@ public interface ClusterRepository { */ List findByWorld(String world); + /** + * Returns all clusters across all worlds. + */ + List findAll(); + /** * Persists the given cluster. Implementations may insert or update as needed. * @@ -50,4 +55,24 @@ public interface ClusterRepository { * @param id the cluster id */ void deleteById(long id); + + /** + * Update world for all clusters from oldWorld to newWorld. + */ + void updateWorldAll(String oldWorld, String newWorld); + + /** + * Update world for clusters overlapping the given bounds in oldWorld. + */ + void updateWorldInBounds(String oldWorld, String newWorld, int minX, int minZ, int maxX, int maxZ); + + /** + * Update world for all clusters from oldWorld to newWorld. + */ + void replaceWorld(String oldWorld, String newWorld); + + /** + * Update world for clusters overlapping the given bounds in oldWorld. + */ + void replaceWorldInBounds(String oldWorld, String newWorld, com.plotsquared.core.plot.PlotId min, com.plotsquared.core.plot.PlotId max); } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterSettingsRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterSettingsRepository.java new file mode 100644 index 0000000000..c5389a84d4 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterSettingsRepository.java @@ -0,0 +1,26 @@ +package com.plotsquared.core.persistence.repository.api; + +import com.plotsquared.core.persistence.entity.ClusterSettingsEntity; + +import java.util.Optional; + +/** + * Repository abstraction for managing cluster settings operations. + */ +public interface ClusterSettingsRepository { + /** + * Find settings for a given cluster id. + * + * @param clusterId the cluster id + * @return optional settings entity + */ + Optional findById(long clusterId); + + /** + * Update the "position" setting for a cluster. + * + * @param clusterId the cluster id + * @param position the new position string + */ + void updatePosition(long clusterId, String position); +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotDeniedRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotDeniedRepository.java index 852bb3bf2c..45ba7903f1 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotDeniedRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotDeniedRepository.java @@ -33,4 +33,11 @@ public interface PlotDeniedRepository { * @param userUuid the user's UUID (String representation) */ void remove(long plotId, String userUuid); + + /** + * Removes all denied users for the specified plot. + * + * @param plotId the unique identifier of the plot + */ + void deleteByPlotId(long plotId); } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotMembershipRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotMembershipRepository.java index 891f9bf98d..a45493ada1 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotMembershipRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotMembershipRepository.java @@ -31,4 +31,11 @@ public interface PlotMembershipRepository { * @param userUuid the user's UUID (String representation) */ void remove(long plotId, String userUuid); + + /** + * Removes all members for the specified plot. + * + * @param plotId the unique identifier of the plot + */ + void deleteByPlotId(long plotId); } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java index e1b5a64f37..d5fff465f0 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java @@ -23,10 +23,34 @@ public interface PlotRepository { */ boolean swapPlots(Plot plot1, Plot plot2); + void replaceWorldAll(String oldWorld, String newWorld); + void movePlots(Plot originPlot, Plot newPlot); void setOwner(Plot plot, UUID newOwner); + /** + * Bulk update world name for plots within the given rectangular plot-id range. + * + * @param oldWorld the source world name + * @param newWorld the destination world name + * @param minX minimum plot x-id (inclusive) + * @param minZ minimum plot z-id (inclusive) + * @param maxX maximum plot x-id (inclusive) + * @param maxZ maximum plot z-id (inclusive) + */ + void replaceWorldInRange(String oldWorld, String newWorld, int minX, int minZ, int maxX, int maxZ); + + /** + * Bulk update world name for all plots in a given world. + */ + void replaceWorld(String oldWorld, String newWorld); + + /** + * Bulk update world name for plots within the given rectangular plot-id bounds. + */ + void replaceWorldInBounds(String oldWorld, String newWorld, com.plotsquared.core.plot.PlotId min, com.plotsquared.core.plot.PlotId max); + /** * Bulk-creates plots and associated data (settings, flags, memberships) * in a single transactional operation. @@ -53,6 +77,14 @@ public interface PlotRepository { */ void createPlotAndSettings(Plot plot); + /** + * Load all plots (with settings, flags and tiers) grouped by world and PlotId. + * Mirrors the legacy SQLManager#getPlots structure. + * + * @return world -> (PlotId -> Plot) + */ + java.util.HashMap> getPlots(); + /** * Finds a plot by its primary identifier. * @@ -127,4 +159,14 @@ public interface PlotRepository { * @param plot the plot to delete */ void delete(Plot plot); + + /** + * Purge plots and all related data by internal database ids. + */ + void purgeIds(java.util.Set ids); + + /** + * Purge plots by world and plot-id coordinates. + */ + void purgeByWorldAndPlotIds(String world, java.util.Set plotIds); } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotSettingsRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotSettingsRepository.java index 395845752c..3eedba2036 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotSettingsRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotSettingsRepository.java @@ -29,4 +29,24 @@ public interface PlotSettingsRepository { * @param plotId the plot identifier */ void deleteByPlotId(long plotId); + + /** + * Updates the alias for the plot settings row of the given plot id. + */ + void updateAlias(long plotId, String alias); + + /** + * Updates the home position string for the plot settings row of the given plot id. + */ + void updatePosition(long plotId, String position); + + /** + * Updates the merged bitmask for the plot settings row of the given plot id. + */ + void updateMerged(long plotId, int mergedBitmask); + + /** + * Creates a default settings row for the plot if it does not exist. + */ + void createDefaultIfAbsent(long plotId, String defaultPosition); } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotTrustedRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotTrustedRepository.java index fe2283092f..224ce8850b 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotTrustedRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotTrustedRepository.java @@ -32,4 +32,11 @@ public interface PlotTrustedRepository { * @param userUuid the user's UUID (String representation) */ void remove(long plotId, String userUuid); + + /** + * Removes all trusted users for the specified plot. + * + * @param plotId the unique identifier of the plot + */ + void deleteByPlotId(long plotId); } From 16432f98d19f33b087ca44e8bcb8c1645856c578 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Thu, 4 Sep 2025 21:50:31 +0200 Subject: [PATCH 046/141] feat: implement cluster and plot repository methods for world updates and settings management --- .../repository/jpa/ClusterRepositoryJpa.java | 60 +++ .../jpa/ClusterSettingsRepositoryJpa.java | 54 ++ .../jpa/PlotDeniedRepositoryJpa.java | 17 + .../jpa/PlotMembershipRepositoryJpa.java | 17 + .../repository/jpa/PlotRepositoryJpa.java | 491 ++++++++++++++++-- .../jpa/PlotSettingsRepositoryJpa.java | 86 +++ .../jpa/PlotTrustedRepositoryJpa.java | 17 + 7 files changed, 710 insertions(+), 32 deletions(-) create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterSettingsRepositoryJpa.java diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterRepositoryJpa.java index 94b2c189c1..9a9fd79d03 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterRepositoryJpa.java @@ -53,6 +53,15 @@ public List findByWorld(String world) { } finally { em.close(); } } + @Override + public List findAll() { + EntityManager em = emf.createEntityManager(); + try { + return em.createQuery("SELECT c FROM ClusterEntity c", ClusterEntity.class) + .getResultList(); + } finally { em.close(); } + } + @Override public void save(ClusterEntity cluster) { EntityManager em = emf.createEntityManager(); @@ -89,4 +98,55 @@ public void deleteById(long id) { throw ex; } finally { em.close(); } } + + @Override + public void updateWorldAll(String oldWorld, String newWorld) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + em.createQuery("UPDATE ClusterEntity c SET c.world = :newWorld WHERE c.world = :oldWorld") + .setParameter("newWorld", newWorld) + .setParameter("oldWorld", oldWorld) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to update cluster world (all) oldWorld={}, newWorld={}", oldWorld, newWorld, ex); + throw ex; + } finally { em.close(); } + } + + @Override + public void updateWorldInBounds(String oldWorld, String newWorld, int minX, int minZ, int maxX, int maxZ) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + em.createQuery("UPDATE ClusterEntity c SET c.world = :newWorld WHERE c.world = :oldWorld AND c.pos1X <= :maxX AND c.pos1Z <= :maxZ AND c.pos2X >= :minX AND c.pos2Z >= :minZ") + .setParameter("newWorld", newWorld) + .setParameter("oldWorld", oldWorld) + .setParameter("minX", minX) + .setParameter("minZ", minZ) + .setParameter("maxX", maxX) + .setParameter("maxZ", maxZ) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to update cluster world in bounds oldWorld={}, newWorld={}, bounds=[{}..{}]x[{}..{}]", oldWorld, newWorld, minX, maxX, minZ, maxZ, ex); + throw ex; + } finally { em.close(); } + } + + @Override + public void replaceWorld(String oldWorld, String newWorld) { + updateWorldAll(oldWorld, newWorld); + } + + @Override + public void replaceWorldInBounds(String oldWorld, String newWorld, com.plotsquared.core.plot.PlotId min, com.plotsquared.core.plot.PlotId max) { + if (min == null || max == null) return; + updateWorldInBounds(oldWorld, newWorld, min.getX(), min.getY(), max.getX(), max.getY()); + } } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterSettingsRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterSettingsRepositoryJpa.java new file mode 100644 index 0000000000..1a8d4744c2 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterSettingsRepositoryJpa.java @@ -0,0 +1,54 @@ +package com.plotsquared.core.persistence.repository.jpa; + +import com.google.inject.Inject; +import com.plotsquared.core.persistence.entity.ClusterSettingsEntity; +import com.plotsquared.core.persistence.repository.api.ClusterSettingsRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.Optional; + +public class ClusterSettingsRepositoryJpa implements ClusterSettingsRepository { + + private static final Logger LOGGER = LogManager.getLogger(ClusterSettingsRepositoryJpa.class); + + private final EntityManagerFactory emf; + + @Inject + public ClusterSettingsRepositoryJpa(EntityManagerFactory emf) { + this.emf = emf; + } + + @Override + public Optional findById(long clusterId) { + EntityManager em = emf.createEntityManager(); + try { + return Optional.ofNullable(em.find(ClusterSettingsEntity.class, clusterId)); + } finally { + em.close(); + } + } + + @Override + public void updatePosition(long clusterId, String position) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + em.createNamedQuery("ClusterSettings.updatePosition") + .setParameter("clusterId", clusterId) + .setParameter("pos", position) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to update cluster position (clusterId={}, position={})", clusterId, position, ex); + throw ex; + } finally { + em.close(); + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotDeniedRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotDeniedRepositoryJpa.java index 20c6d1a844..9fd0033e60 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotDeniedRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotDeniedRepositoryJpa.java @@ -67,4 +67,21 @@ public void remove(long plotId, String userUuid) { throw ex; } finally { em.close(); } } + + @Override + public void deleteByPlotId(long plotId) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + em.createQuery("DELETE FROM PlotDeniedEntity e WHERE e.plotId = :plotId") + .setParameter("plotId", plotId) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to delete all plot denied users (plotId={})", plotId, ex); + throw ex; + } finally { em.close(); } + } } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotMembershipRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotMembershipRepositoryJpa.java index 696ff7cc98..1383c69a90 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotMembershipRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotMembershipRepositoryJpa.java @@ -67,4 +67,21 @@ public void remove(long plotId, String userUuid) { throw ex; } finally { em.close(); } } + + @Override + public void deleteByPlotId(long plotId) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + em.createQuery("DELETE FROM PlotMembershipEntity e WHERE e.plotId = :plotId") + .setParameter("plotId", plotId) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to delete all plot members (plotId={})", plotId, ex); + throw ex; + } finally { em.close(); } + } } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java index 5f2d5bb5ef..c502594d93 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java @@ -32,8 +32,13 @@ public boolean createPlotSafe(final Plot plot) { try { tx.begin(); String world = null; - try { world = plot.getWorldName(); } catch (Throwable ignored) {} - if (world == null) { world = plot.getArea().toString(); } + try { + world = plot.getWorldName(); + } catch (Throwable ignored) { + } + if (world == null) { + world = plot.getArea().toString(); + } Optional existing = findByWorldAndId(world, plot.getId().getX(), plot.getId().getY()); if (existing.isPresent()) { tx.commit(); @@ -43,7 +48,10 @@ public boolean createPlotSafe(final Plot plot) { pe.setPlotIdX(plot.getId().getX()); pe.setPlotIdZ(plot.getId().getY()); UUID ownerUuid = null; - try { ownerUuid = plot.getOwnerAbs(); } catch (Throwable ignored) {} + try { + ownerUuid = plot.getOwnerAbs(); + } catch (Throwable ignored) { + } pe.setOwner(ownerUuid != null ? ownerUuid.toString() : com.plotsquared.core.database.DBFunc.EVERYONE.toString()); pe.setWorld(world); em.persist(pe); @@ -58,7 +66,9 @@ public boolean createPlotSafe(final Plot plot) { tx.commit(); return true; } catch (RuntimeException e) { - if (tx.isActive()) tx.rollback(); + if (tx.isActive()) { + tx.rollback(); + } LOGGER.error("Failed to create plot safely (plot={})", plot, e); throw e; } finally { @@ -73,13 +83,21 @@ public void createPlotAndSettings(final Plot plot) { try { tx.begin(); String world = null; - try { world = plot.getWorldName(); } catch (Throwable ignored) {} - if (world == null) { world = plot.getArea().toString(); } + try { + world = plot.getWorldName(); + } catch (Throwable ignored) { + } + if (world == null) { + world = plot.getArea().toString(); + } PlotEntity pe = new PlotEntity(); pe.setPlotIdX(plot.getId().getX()); pe.setPlotIdZ(plot.getId().getY()); UUID ownerUuid = null; - try { ownerUuid = plot.getOwnerAbs(); } catch (Throwable ignored) {} + try { + ownerUuid = plot.getOwnerAbs(); + } catch (Throwable ignored) { + } pe.setOwner(ownerUuid != null ? ownerUuid.toString() : com.plotsquared.core.database.DBFunc.EVERYONE.toString()); pe.setWorld(world); em.persist(pe); @@ -93,7 +111,9 @@ public void createPlotAndSettings(final Plot plot) { em.persist(se); tx.commit(); } catch (RuntimeException e) { - if (tx.isActive()) tx.rollback(); + if (tx.isActive()) { + tx.rollback(); + } LOGGER.error("Failed to create plot and settings (plot={})", plot, e); throw e; } finally { @@ -116,12 +136,20 @@ public void createPlotsAndData(final List plots) { pe.setPlotIdX(plot.getId().getX()); pe.setPlotIdZ(plot.getId().getY()); java.util.UUID ownerUuid = null; - try { ownerUuid = plot.getOwnerAbs(); } catch (Throwable ignored) {} + try { + ownerUuid = plot.getOwnerAbs(); + } catch (Throwable ignored) { + } pe.setOwner(ownerUuid != null ? ownerUuid.toString() : com.plotsquared.core.database.DBFunc.EVERYONE.toString()); // Prefer world name for consistency with other queries String world = null; - try { world = plot.getWorldName(); } catch (Throwable ignored) {} - if (world == null) { world = plot.getArea().toString(); } + try { + world = plot.getWorldName(); + } catch (Throwable ignored) { + } + if (world == null) { + world = plot.getArea().toString(); + } pe.setWorld(world); em.persist(pe); em.flush(); // ensure ID is generated @@ -157,7 +185,13 @@ public void createPlotsAndData(final List plots) { } } catch (Throwable t) { // log and continue - LOGGER.warn("Failed to persist settings for plot (x={}, z={}, world={})", plot.getId().getX(), plot.getId().getY(), world, t); + LOGGER.warn( + "Failed to persist settings for plot (x={}, z={}, world={})", + plot.getId().getX(), + plot.getId().getY(), + world, + t + ); } // Persist flags @@ -173,7 +207,13 @@ public void createPlotsAndData(final List plots) { } } } catch (Throwable t) { - LOGGER.warn("Failed to persist flags for plot (x={}, z={}, world={})", plot.getId().getX(), plot.getId().getY(), world, t); + LOGGER.warn( + "Failed to persist flags for plot (x={}, z={}, world={})", + plot.getId().getX(), + plot.getId().getY(), + world, + t + ); } // Persist tiers: NOTE legacy mapping members->trusted, trusted->helpers @@ -200,12 +240,20 @@ public void createPlotsAndData(final List plots) { em.persist(e); } } catch (Throwable t) { - LOGGER.warn("Failed to persist tiers for plot (x={}, z={}, world={})", plot.getId().getX(), plot.getId().getY(), world, t); + LOGGER.warn( + "Failed to persist tiers for plot (x={}, z={}, world={})", + plot.getId().getX(), + plot.getId().getY(), + world, + t + ); } } tx.commit(); } catch (RuntimeException e) { - if (tx.isActive()) tx.rollback(); + if (tx.isActive()) { + tx.rollback(); + } LOGGER.error("Failed bulk create plots and data", e); throw e; } finally { @@ -219,12 +267,16 @@ public boolean swapPlots(final Plot plot1, final Plot plot2) { EntityTransaction tx = em.getTransaction(); try { tx.begin(); - var plot1Id = findByXAndZAnyWorld(plot1.getId().getX(), plot1.getId().getY(), plot1.getWorldName()).orElseThrow().getId(); - var plot2Id = findByXAndZAnyWorld(plot2.getId().getX(), plot2.getId().getY(), plot2.getWorldName()).orElseThrow().getId(); + var plot1Id = findByXAndZAnyWorld(plot1.getId().getX(), plot1.getId().getY(), plot1.getWorldName()) + .orElseThrow() + .getId(); + var plot2Id = findByXAndZAnyWorld(plot2.getId().getX(), plot2.getId().getY(), plot2.getWorldName()) + .orElseThrow() + .getId(); em.createNamedQuery("Plot.updateXANDZ") - .setParameter("id", plot1Id) - .setParameter("x", plot1.getId().getX()) - .setParameter("z", plot1.getId().getY()); + .setParameter("id", plot1Id) + .setParameter("x", plot1.getId().getX()) + .setParameter("z", plot1.getId().getY()); em.createNamedQuery("Plot.updateXANDZ") .setParameter("id", plot2Id) .setParameter("x", plot2.getId().getX()) @@ -232,11 +284,57 @@ public boolean swapPlots(final Plot plot1, final Plot plot2) { tx.commit(); return true; } catch (RuntimeException e) { - if (tx.isActive()) tx.rollback(); + if (tx.isActive()) { + tx.rollback(); + } } return false; } + @Override + public void replaceWorldInRange(String oldWorld, String newWorld, int minX, int minZ, int maxX, int maxZ) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + em.createQuery("UPDATE PlotEntity p SET p.world = :newWorld WHERE p.world = :oldWorld AND p.plotIdX BETWEEN :minX AND :maxX AND p.plotIdZ BETWEEN :minZ AND :maxZ") + .setParameter("newWorld", newWorld) + .setParameter("oldWorld", oldWorld) + .setParameter("minX", minX) + .setParameter("maxX", maxX) + .setParameter("minZ", minZ) + .setParameter("maxZ", maxZ) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to replace world in range (oldWorld={}, newWorld={}, range=[{}..{}]x[{}..{}])", oldWorld, newWorld, minX, maxX, minZ, maxZ, e); + throw e; + } finally { + em.close(); + } + } + + @Override + public void replaceWorldAll(String oldWorld, String newWorld) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + em.createQuery("UPDATE PlotEntity p SET p.world = :newWorld WHERE p.world = :oldWorld") + .setParameter("newWorld", newWorld) + .setParameter("oldWorld", oldWorld) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to replace world (all plots) oldWorld={}, newWorld={}", oldWorld, newWorld, e); + throw e; + } finally { + em.close(); + } + } + @Override public void movePlots(final Plot originPlot, final Plot newPlot) { EntityManager em = emf.createEntityManager(); @@ -255,7 +353,9 @@ public void movePlots(final Plot originPlot, final Plot newPlot) { .setParameter("world", newPlot.getWorldName()); tx.commit(); } catch (RuntimeException e) { - if (tx.isActive()) tx.rollback(); + if (tx.isActive()) { + tx.rollback(); + } LOGGER.error("Failed to move plots (plot1={}, plot2={})", originPlot, newPlot, e); throw e; } @@ -274,7 +374,9 @@ public void setOwner(final Plot plot, final UUID newOwner) { .setParameter("owner", newOwner); tx.commit(); } catch (RuntimeException e) { - if (tx.isActive()) tx.rollback(); + if (tx.isActive()) { + tx.rollback(); + } LOGGER.error("Failed to set plot owner (plot={}, newOwner={})", plot, newOwner, e); throw e; } @@ -355,8 +457,17 @@ public void save(PlotEntity plot) { } tx.commit(); } catch (RuntimeException e) { - if (tx.isActive()) tx.rollback(); - LOGGER.error("Failed to save plot (id={}, world={}, x={}, z={})", plot.getId(), plot.getWorld(), plot.getPlotIdX(), plot.getPlotIdZ(), e); + if (tx.isActive()) { + tx.rollback(); + } + LOGGER.error( + "Failed to save plot (id={}, world={}, x={}, z={})", + plot.getId(), + plot.getWorld(), + plot.getPlotIdX(), + plot.getPlotIdZ(), + e + ); throw e; } finally { em.close(); @@ -375,7 +486,9 @@ public void deleteById(long id) { } tx.commit(); } catch (RuntimeException e) { - if (tx.isActive()) tx.rollback(); + if (tx.isActive()) { + tx.rollback(); + } LOGGER.error("Failed to delete plot by id (id={})", id, e); throw e; } finally { @@ -390,8 +503,13 @@ public void deleteRatings(final Plot plot) { try { tx.begin(); String world = null; - try { world = plot.getWorldName(); } catch (Throwable ignored) {} - if (world == null) { world = plot.getArea().toString(); } + try { + world = plot.getWorldName(); + } catch (Throwable ignored) { + } + if (world == null) { + world = plot.getArea().toString(); + } PlotEntity pe = em.createNamedQuery("Plot.findByWorldAndId", PlotEntity.class) .setParameter("world", world) .setParameter("x", plot.getId().getX()) @@ -404,7 +522,9 @@ public void deleteRatings(final Plot plot) { } tx.commit(); } catch (RuntimeException e) { - if (tx.isActive()) tx.rollback(); + if (tx.isActive()) { + tx.rollback(); + } LOGGER.error("Failed to delete ratings for plot (plot={})", plot, e); throw e; } finally { @@ -419,8 +539,13 @@ public void delete(final Plot plot) { try { tx.begin(); String world = null; - try { world = plot.getWorldName(); } catch (Throwable ignored) {} - if (world == null) { world = plot.getArea().toString(); } + try { + world = plot.getWorldName(); + } catch (Throwable ignored) { + } + if (world == null) { + world = plot.getArea().toString(); + } PlotEntity pe = em.createNamedQuery("Plot.findByWorldAndId", PlotEntity.class) .setParameter("world", world) .setParameter("x", plot.getId().getX()) @@ -454,11 +579,313 @@ public void delete(final Plot plot) { } tx.commit(); } catch (RuntimeException e) { - if (tx.isActive()) tx.rollback(); + if (tx.isActive()) { + tx.rollback(); + } LOGGER.error("Failed to delete plot (plot={})", plot, e); throw e; } finally { em.close(); } } + + @Override + public java.util.HashMap> getPlots() { + EntityManager em = emf.createEntityManager(); + try { + java.util.HashMap> worldMap = new java.util.HashMap<>(); + java.util.Map byId = new java.util.HashMap<>(); + java.util.Map uuidCache = new java.util.HashMap<>(); + + // Load plots + List plots = em.createQuery("SELECT p FROM PlotEntity p", PlotEntity.class).getResultList(); + for (PlotEntity p : plots) { + String ownerStr = p.getOwner(); + java.util.UUID owner; + if (ownerStr == null) { + owner = com.plotsquared.core.database.DBFunc.EVERYONE; + } else { + owner = uuidCache.get(ownerStr); + if (owner == null) { + try { + owner = java.util.UUID.fromString(ownerStr); + } catch (IllegalArgumentException ex) { + String base = com.plotsquared.core.configuration.Settings.UUID.FORCE_LOWERCASE + ? ("OfflinePlayer:" + ownerStr.toLowerCase()) + : ("OfflinePlayer:" + ownerStr); + owner = java.util.UUID.nameUUIDFromBytes(base.getBytes(java.nio.charset.StandardCharsets.UTF_8)); + } + uuidCache.put(ownerStr, owner); + } + } + long time = p.getTimestamp() != null ? p.getTimestamp().getTime() : System.currentTimeMillis(); + com.plotsquared.core.plot.PlotId pid = com.plotsquared.core.plot.PlotId.of(p.getPlotIdX(), p.getPlotIdZ()); + com.plotsquared.core.plot.Plot plot = new com.plotsquared.core.plot.Plot( + pid, + owner, + new java.util.HashSet<>(), + new java.util.HashSet<>(), + new java.util.HashSet<>(), + "", + null, + null, + null, + new boolean[]{false, false, false, false}, + time, + p.getId() != null ? p.getId().intValue() : -1 + ); + worldMap.computeIfAbsent(p.getWorld(), k -> new java.util.HashMap<>()).put(pid, plot); + if (p.getId() != null) { + byId.put(p.getId(), plot); + } + } + + // Ratings (optional) + if (com.plotsquared.core.configuration.Settings.Enabled_Components.RATING_CACHE) { + var ratings = em.createQuery( + "SELECT r FROM PlotRatingEntity r", + com.plotsquared.core.persistence.entity.PlotRatingEntity.class + ).getResultList(); + for (var r : ratings) { + var plot = byId.get(r.getPlotId()); + if (plot != null) { + try { + plot.getSettings().getRatings().put(java.util.UUID.fromString(r.getPlayer()), r.getRating()); + } catch (IllegalArgumentException ignored) { + } + } + } + } + + // Helpers -> trusted + var helpers = em.createQuery( + "SELECT e FROM PlotMembershipEntity e", + com.plotsquared.core.persistence.entity.PlotMembershipEntity.class + ).getResultList(); + for (var e : helpers) { + var plot = byId.get(e.getPlotId()); + if (plot != null) { + try { + plot.getTrusted().add(java.util.UUID.fromString(e.getUserUuid())); + } catch (IllegalArgumentException ignored) { + } + } + } + + // Trusted -> members + var trusted = em.createQuery( + "SELECT e FROM PlotTrustedEntity e", + com.plotsquared.core.persistence.entity.PlotTrustedEntity.class + ).getResultList(); + for (var e : trusted) { + var plot = byId.get(e.getPlotId()); + if (plot != null) { + try { + plot.getMembers().add(java.util.UUID.fromString(e.getUserUuid())); + } catch (IllegalArgumentException ignored) { + } + } + } + + // Denied + var denied = em.createQuery( + "SELECT e FROM PlotDeniedEntity e", + com.plotsquared.core.persistence.entity.PlotDeniedEntity.class + ).getResultList(); + for (var e : denied) { + var plot = byId.get(e.getPlotId()); + if (plot != null) { + try { + plot.getDenied().add(java.util.UUID.fromString(e.getUserUuid())); + } catch (IllegalArgumentException ignored) { + } + } + } + + // Flags + try { + com.plotsquared.core.plot.flag.types.BlockTypeListFlag.skipCategoryVerification = true; + } catch (Throwable ignored) { + } + var flags = em.createQuery( + "SELECT f FROM PlotFlagEntity f", + com.plotsquared.core.persistence.entity.PlotFlagEntity.class + ).getResultList(); + for (var f : flags) { + var plot = byId.get(f.getPlot().getId()); + if (plot != null) { + String flag = f.getFlag(); + String value = f.getValue(); + var registry = com.plotsquared.core.plot.flag.GlobalFlagContainer.getInstance(); + var plotFlag = registry.getFlagFromString(flag); + if (plotFlag == null) { + plot.getFlagContainer().addUnknownFlag(flag, value); + } else { + try { + plot.getFlagContainer().addFlag(plotFlag.parse(value)); + } catch (Exception ex) { + // ignore invalid + } + } + } + } + try { + com.plotsquared.core.plot.flag.types.BlockTypeListFlag.skipCategoryVerification = false; + } catch (Throwable ignored) { + } + + // Settings + var settings = em.createQuery( + "SELECT s FROM PlotSettingsEntity s", + com.plotsquared.core.persistence.entity.PlotSettingsEntity.class + ).getResultList(); + for (var s : settings) { + var plot = byId.get(s.getId()); + if (plot != null) { + if (s.getAlias() != null) { + plot.getSettings().setAlias(s.getAlias()); + } + String pos = s.getPosition(); + if (pos != null) { + String lower = pos.toLowerCase(); + if (!lower.isEmpty() && !"default".equals(lower) && !"0,0,0".equals(lower) && !"center".equals(lower) && !"centre".equals( + lower)) { + try { + plot.getSettings().setPosition(com.plotsquared.core.location.BlockLoc.fromString(pos)); + } catch (Throwable ignored) { + } + } + } + Integer m = s.getMerged(); + if (m != null) { + boolean[] merged = new boolean[4]; + for (int i = 0; i < 4; i++) { + merged[3 - i] = ((m & (1 << i)) != 0); + } + plot.getSettings().setMerged(merged); + } + } + } + + return worldMap; + } finally { + em.close(); + } + } + + @Override + public void purgeIds(java.util.Set ids) { + if (ids == null || ids.isEmpty()) return; + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + // Convert Integer to Long (plot ids are Long) + java.util.Set longIds = new java.util.HashSet<>(); + for (Integer i : ids) { + if (i != null) longIds.add(i.longValue()); + } + if (longIds.isEmpty()) { + tx.commit(); + return; + } + // Delete child tables first + em.createQuery("DELETE FROM PlotFlagEntity f WHERE f.plot.id IN :ids") + .setParameter("ids", longIds) + .executeUpdate(); + em.createQuery("DELETE FROM PlotMembershipEntity e WHERE e.plotId IN :ids") + .setParameter("ids", longIds) + .executeUpdate(); + em.createQuery("DELETE FROM PlotTrustedEntity e WHERE e.plotId IN :ids") + .setParameter("ids", longIds) + .executeUpdate(); + em.createQuery("DELETE FROM PlotDeniedEntity e WHERE e.plotId IN :ids") + .setParameter("ids", longIds) + .executeUpdate(); + em.createQuery("DELETE FROM PlotRatingEntity r WHERE r.plotId IN :ids") + .setParameter("ids", longIds) + .executeUpdate(); + em.createQuery("DELETE FROM PlotSettingsEntity s WHERE s.id IN :ids") + .setParameter("ids", longIds) + .executeUpdate(); + // Finally delete plots + em.createQuery("DELETE FROM PlotEntity p WHERE p.id IN :ids") + .setParameter("ids", longIds) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to purge plots by ids (ids={})", ids, e); + throw e; + } finally { + em.close(); + } + } + + @Override + public void purgeByWorldAndPlotIds(String world, java.util.Set plotIds) { + if (world == null || world.isEmpty() || plotIds == null || plotIds.isEmpty()) return; + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + // Resolve plot ids by fetching candidates in the world and filtering in-memory + List ids = new java.util.ArrayList<>(); + List candidates = em.createNamedQuery("Plot.findByWorld", PlotEntity.class) + .setParameter("world", world) + .getResultList(); + java.util.HashSet lookup = new java.util.HashSet<>(plotIds); + for (PlotEntity p : candidates) { + if (lookup.contains(com.plotsquared.core.plot.PlotId.of(p.getPlotIdX(), p.getPlotIdZ())) && p.getId() != null) { + ids.add(p.getId()); + } + } + if (ids.isEmpty()) { + tx.commit(); + return; + } + java.util.Set longIds = new java.util.HashSet<>(ids); + // Delete child tables first + em.createQuery("DELETE FROM PlotFlagEntity f WHERE f.plot.id IN :ids") + .setParameter("ids", longIds) + .executeUpdate(); + em.createQuery("DELETE FROM PlotMembershipEntity e WHERE e.plotId IN :ids") + .setParameter("ids", longIds) + .executeUpdate(); + em.createQuery("DELETE FROM PlotTrustedEntity e WHERE e.plotId IN :ids") + .setParameter("ids", longIds) + .executeUpdate(); + em.createQuery("DELETE FROM PlotDeniedEntity e WHERE e.plotId IN :ids") + .setParameter("ids", longIds) + .executeUpdate(); + em.createQuery("DELETE FROM PlotRatingEntity r WHERE r.plotId IN :ids") + .setParameter("ids", longIds) + .executeUpdate(); + em.createQuery("DELETE FROM PlotSettingsEntity s WHERE s.id IN :ids") + .setParameter("ids", longIds) + .executeUpdate(); + // Finally delete plots + em.createQuery("DELETE FROM PlotEntity p WHERE p.id IN :ids") + .setParameter("ids", longIds) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to purge plots by world/id (world={}, plotIds={})", world, plotIds, e); + throw e; + } finally { + em.close(); + } + } + + @Override + public void replaceWorld(String oldWorld, String newWorld) { + replaceWorldAll(oldWorld, newWorld); + } + + @Override + public void replaceWorldInBounds(String oldWorld, String newWorld, com.plotsquared.core.plot.PlotId min, com.plotsquared.core.plot.PlotId max) { + if (min == null || max == null) return; + replaceWorldInRange(oldWorld, newWorld, min.getX(), min.getY(), max.getX(), max.getY()); + } } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotSettingsRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotSettingsRepositoryJpa.java index 67f6b54982..a54ac8b30f 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotSettingsRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotSettingsRepositoryJpa.java @@ -72,4 +72,90 @@ public void deleteByPlotId(long plotId) { em.close(); } } + + @Override + public void updateAlias(long plotId, String alias) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + em.createNamedQuery("PlotSettings.updateAlias") + .setParameter("plotId", plotId) + .setParameter("alias", alias) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to update alias (plotId={})", plotId, ex); + throw ex; + } finally { + em.close(); + } + } + + @Override + public void updatePosition(long plotId, String position) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + em.createNamedQuery("PlotSettings.updatePosition") + .setParameter("plotId", plotId) + .setParameter("pos", position) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to update position (plotId={})", plotId, ex); + throw ex; + } finally { + em.close(); + } + } + + @Override + public void updateMerged(long plotId, int mergedBitmask) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + em.createNamedQuery("PlotSettings.updateMerged") + .setParameter("plotId", plotId) + .setParameter("merged", mergedBitmask) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to update merged (plotId={})", plotId, ex); + throw ex; + } finally { + em.close(); + } + } + + @Override + public void createDefaultIfAbsent(long plotId, String defaultPosition) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + PlotSettingsEntity existing = em.find(PlotSettingsEntity.class, plotId); + if (existing == null) { + PlotSettingsEntity se = new PlotSettingsEntity(); + se.setId(plotId); + // attach plot reference to satisfy FK if needed + com.plotsquared.core.persistence.entity.PlotEntity pe = em.getReference(com.plotsquared.core.persistence.entity.PlotEntity.class, plotId); + se.setPlot(pe); + se.setPosition(defaultPosition); + em.persist(se); + } + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to create default settings if absent (plotId={})", plotId, ex); + throw ex; + } finally { + em.close(); + } + } } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotTrustedRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotTrustedRepositoryJpa.java index f2491b2660..af86215881 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotTrustedRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotTrustedRepositoryJpa.java @@ -67,4 +67,21 @@ public void remove(long plotId, String userUuid) { throw ex; } finally { em.close(); } } + + @Override + public void deleteByPlotId(long plotId) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + em.createQuery("DELETE FROM PlotTrustedEntity e WHERE e.plotId = :plotId") + .setParameter("plotId", plotId) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to delete all plot trusted users (plotId={})", plotId, ex); + throw ex; + } finally { em.close(); } + } } From c900f8471afeb1cae3e7a729689c5943afd47d03 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Thu, 4 Sep 2025 21:50:39 +0200 Subject: [PATCH 047/141] feat: add named queries for updating cluster and plot settings entities --- .../core/persistence/entity/ClusterSettingsEntity.java | 3 +++ .../core/persistence/entity/PlotDeniedEntity.java | 3 ++- .../core/persistence/entity/PlotSettingsEntity.java | 5 +++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterSettingsEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterSettingsEntity.java index d4474b4f61..c184f44d8f 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterSettingsEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterSettingsEntity.java @@ -10,6 +10,9 @@ @Entity @Table(name = "cluster_settings") +@jakarta.persistence.NamedQueries({ + @jakarta.persistence.NamedQuery(name = "ClusterSettings.updatePosition", query = "UPDATE ClusterSettingsEntity s SET s.position = :pos WHERE s.id = :clusterId") +}) public class ClusterSettingsEntity { @Id @Column(name = "cluster_id") diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotDeniedEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotDeniedEntity.java index 6b956d861e..948755f3ef 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotDeniedEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotDeniedEntity.java @@ -13,7 +13,8 @@ @IdClass(PlotUserId.class) @NamedQueries({ @NamedQuery(name = "PlotDenied.delete", query = "DELETE FROM PlotDeniedEntity e WHERE e.plotId = :plotId AND e.userUuid = :uuid"), - @NamedQuery(name = "PlotDenied.findUsers", query = "SELECT e.userUuid FROM PlotDeniedEntity e WHERE e.plotId = :plotId") + @NamedQuery(name = "PlotDenied.findUsers", query = "SELECT e.userUuid FROM PlotDeniedEntity e WHERE e.plotId = :plotId"), + @NamedQuery(name = "PlotDenied.deleteAll", query = "DELETE FROM PlotDeniedEntity e WHERE e.plotId = :plotId") }) public class PlotDeniedEntity { @Id diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotSettingsEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotSettingsEntity.java index 4e7a5f0dc5..e95561fdde 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotSettingsEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotSettingsEntity.java @@ -10,6 +10,11 @@ @Entity @Table(name = "plot_settings") +@jakarta.persistence.NamedQueries({ + @jakarta.persistence.NamedQuery(name = "PlotSettings.updateAlias", query = "UPDATE PlotSettingsEntity s SET s.alias = :alias WHERE s.id = :plotId"), + @jakarta.persistence.NamedQuery(name = "PlotSettings.updatePosition", query = "UPDATE PlotSettingsEntity s SET s.position = :pos WHERE s.id = :plotId"), + @jakarta.persistence.NamedQuery(name = "PlotSettings.updateMerged", query = "UPDATE PlotSettingsEntity s SET s.merged = :merged WHERE s.id = :plotId") +}) public class PlotSettingsEntity { @Id @Column(name = "plot_plot_id") From 961509f4deddd7164ce398924dda8c3b8d085093 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Thu, 4 Sep 2025 21:50:45 +0200 Subject: [PATCH 048/141] feat: add binding for ClusterSettingsRepository in PersistenceModule --- .../plotsquared/core/persistence/config/PersistenceModule.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java b/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java index bbcf3acac1..b651b81848 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java @@ -7,6 +7,7 @@ import com.plotsquared.core.persistence.repository.api.ClusterHelperRepository; import com.plotsquared.core.persistence.repository.api.ClusterInvitedRepository; import com.plotsquared.core.persistence.repository.api.ClusterRepository; +import com.plotsquared.core.persistence.repository.api.ClusterSettingsRepository; import com.plotsquared.core.persistence.repository.api.PlayerMetaRepository; import com.plotsquared.core.persistence.repository.api.PlotCommentRepository; import com.plotsquared.core.persistence.repository.api.PlotDeniedRepository; @@ -19,6 +20,7 @@ import com.plotsquared.core.persistence.repository.jpa.ClusterHelperRepositoryJpa; import com.plotsquared.core.persistence.repository.jpa.ClusterInvitedRepositoryJpa; import com.plotsquared.core.persistence.repository.jpa.ClusterRepositoryJpa; +import com.plotsquared.core.persistence.repository.jpa.ClusterSettingsRepositoryJpa; import com.plotsquared.core.persistence.repository.jpa.PlayerMetaRepositoryJpa; import com.plotsquared.core.persistence.repository.jpa.PlotCommentRepositoryJpa; import com.plotsquared.core.persistence.repository.jpa.PlotDeniedRepositoryJpa; @@ -52,6 +54,7 @@ protected void configure() { bind(ClusterRepository.class).to(ClusterRepositoryJpa.class); bind(ClusterHelperRepository.class).to(ClusterHelperRepositoryJpa.class); bind(ClusterInvitedRepository.class).to(ClusterInvitedRepositoryJpa.class); + bind(ClusterSettingsRepository.class).to(ClusterSettingsRepositoryJpa.class); // Eagerly run Flyway migrations on startup bind(FlywayBootstrap.class).asEagerSingleton(); From cab85a9145837bca70b6e4977a8637e5f517e7e7 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Thu, 4 Sep 2025 21:50:50 +0200 Subject: [PATCH 049/141] feat: refactor DBFunc to use repository pattern for plot and cluster management --- .../com/plotsquared/core/database/DBFunc.java | 499 +++++++++++++----- 1 file changed, 355 insertions(+), 144 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java index d837f927b8..9d374e244b 100644 --- a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java +++ b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java @@ -19,11 +19,22 @@ package com.plotsquared.core.database; import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.persistence.entity.ClusterEntity; import com.plotsquared.core.persistence.entity.PlayerMetaEntity; import com.plotsquared.core.persistence.entity.PlotCommentEntity; +import com.plotsquared.core.persistence.entity.PlotEntity; +import com.plotsquared.core.persistence.repository.api.ClusterHelperRepository; +import com.plotsquared.core.persistence.repository.api.ClusterInvitedRepository; +import com.plotsquared.core.persistence.repository.api.ClusterRepository; +import com.plotsquared.core.persistence.repository.api.ClusterSettingsRepository; import com.plotsquared.core.persistence.repository.api.PlayerMetaRepository; import com.plotsquared.core.persistence.repository.api.PlotCommentRepository; +import com.plotsquared.core.persistence.repository.api.PlotDeniedRepository; +import com.plotsquared.core.persistence.repository.api.PlotMembershipRepository; import com.plotsquared.core.persistence.repository.api.PlotRepository; +import com.plotsquared.core.persistence.repository.api.PlotSettingsRepository; +import com.plotsquared.core.persistence.repository.api.PlotTrustedRepository; +import com.plotsquared.core.persistence.repository.api.ClusterSettingsRepository; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotCluster; @@ -32,12 +43,10 @@ import com.plotsquared.core.plot.flag.PlotFlag; import com.plotsquared.core.util.task.RunnableVal; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.SQLException; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -55,11 +64,6 @@ public class DBFunc { public static final UUID EVERYONE = UUID.fromString("1-1-3-3-7"); public static final UUID SERVER = UUID.fromString("00000000-0000-0000-0000-000000000000"); - /** - * Abstract Database Manager - */ - public static AbstractDB dbManager; - public static void addPersistentMeta(UUID uuid, String key, byte[] meta, boolean delete) { try { PlayerMetaRepository repo = PlotSquared.platform().injector().getInstance(PlayerMetaRepository.class); @@ -113,14 +117,6 @@ public static void movePlot(Plot originalPlot, Plot newPlot) { repo.movePlots(originalPlot, newPlot); } - @Deprecated(forRemoval = true) - public static void validatePlots(Set plots) { - if (dbManager == null) { - return; - } - DBFunc.dbManager.validateAllPlots(plots); - } - /** * Set the owner of a plot * @@ -173,12 +169,8 @@ public static void createPlotAndSettings(Plot plot, Runnable whenDone) { * @param plot Plot to delete */ public static void delete(Plot plot) { - if (plot.temp == -1) { - return; - } PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); repo.delete(plot); - plot.temp = -1; } /** @@ -187,9 +179,6 @@ public static void delete(Plot plot) { * @param plot */ public static void deleteRatings(Plot plot) { - if (plot.temp == -1) { - return; - } PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); repo.deleteRatings(plot); } @@ -200,10 +189,16 @@ public static void deleteRatings(Plot plot) { * @param plot */ public static void deleteTrusted(Plot plot) { - if (plot.temp == -1 || dbManager == null) { - return; + try { + PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + String world = plot.getWorldName(); + var peOpt = repo.findByWorldAndId(world, plot.getId().getX(), plot.getId().getY()); + peOpt.ifPresent(pe -> { + PlotMembershipRepository mRepo = PlotSquared.platform().injector().getInstance(PlotMembershipRepository.class); + mRepo.deleteByPlotId(pe.getId()); + }); + } catch (Throwable ignored) { } - DBFunc.dbManager.deleteHelpers(plot); } /** @@ -212,10 +207,16 @@ public static void deleteTrusted(Plot plot) { * @param plot */ public static void deleteMembers(Plot plot) { - if (plot.temp == -1 || dbManager == null) { - return; + try { + PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + String world = plot.getWorldName(); + var peOpt = repo.findByWorldAndId(world, plot.getId().getX(), plot.getId().getY()); + peOpt.ifPresent(pe -> { + PlotTrustedRepository tRepo = PlotSquared.platform().injector().getInstance(PlotTrustedRepository.class); + tRepo.deleteByPlotId(pe.getId()); + }); + } catch (Throwable ignored) { } - DBFunc.dbManager.deleteTrusted(plot); } /** @@ -224,10 +225,16 @@ public static void deleteMembers(Plot plot) { * @param plot */ public static void deleteDenied(Plot plot) { - if (plot.temp == -1 || dbManager == null) { - return; + try { + PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + String world = plot.getWorldName(); + var peOpt = repo.findByWorldAndId(world, plot.getId().getX(), plot.getId().getY()); + peOpt.ifPresent(pe -> { + PlotDeniedRepository dRepo = PlotSquared.platform().injector().getInstance(PlotDeniedRepository.class); + dRepo.deleteByPlotId(pe.getId()); + }); + } catch (Throwable ignored) { } - DBFunc.dbManager.deleteDenied(plot); } /** @@ -236,12 +243,9 @@ public static void deleteDenied(Plot plot) { * @param plot */ public static void deleteComments(Plot plot) { - if (plot.temp == -1) { - return; - } try { - com.plotsquared.core.persistence.repository.api.PlotCommentRepository repo = PlotSquared.platform().injector().getInstance(com.plotsquared.core.persistence.repository.api.PlotCommentRepository.class); - String world = plot.getArea().toString(); + PlotCommentRepository repo = PlotSquared.platform().injector().getInstance(PlotCommentRepository.class); + String world = plot.getWorldName(); int hash = plot.getId().hashCode(); repo.deleteByWorldAndHash(world, hash); } catch (Throwable ignored) { @@ -258,17 +262,34 @@ public static void deleteComments(Plot plot) { * @param plot */ public static void deleteSettings(Plot plot) { - if (plot.temp == -1 || dbManager == null) { - return; + + try { + PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + String world = plot.getWorldName(); + var peOpt = repo.findByWorldAndId(world, plot.getId().getX(), plot.getId().getY()); + peOpt.ifPresent(pe -> { + PlotSettingsRepository sRepo = PlotSquared.platform().injector().getInstance(PlotSettingsRepository.class); + sRepo.deleteByPlotId(pe.getId()); + }); + } catch (Throwable ignored) { } - DBFunc.dbManager.deleteSettings(plot); } public static void delete(PlotCluster toDelete) { - if (dbManager == null) { + if (toDelete == null) { return; } - DBFunc.dbManager.delete(toDelete); + try { + ClusterRepository clusterRepo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); + String world = toDelete.area != null ? toDelete.area.getWorldName() : null; + if (world == null) { + return; + } + PlotId center = toDelete.getCenterPlotId(); + java.util.Optional ce = clusterRepo.findByWorldAndBounds(world, center.getX(), center.getY()); + ce.ifPresent(entity -> clusterRepo.deleteById(entity.getId())); + } catch (Throwable ignored) { + } } /** @@ -278,54 +299,82 @@ public static void delete(PlotCluster toDelete) { * @param plot Plot Object */ public static void createPlotSettings(int id, Plot plot) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.createPlotSettings(id, plot); - } - - /** - * Get a plot id. - * - * @param plot Plot Object - * @return ID - */ - public static int getId(Plot plot) { - if (dbManager == null) { - return 0; + try { + PlotSettingsRepository repo = PlotSquared.platform().injector().getInstance(PlotSettingsRepository.class); + repo.createDefaultIfAbsent(id, "DEFAULT"); + } catch (Throwable ignored) { } - return DBFunc.dbManager.getId(plot); } /** * @return Plots */ public static HashMap> getPlots() { - if (dbManager == null) { - return new HashMap<>(); - } - return DBFunc.dbManager.getPlots(); + PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + return repo.getPlots(); } public static void setMerged(Plot plot, boolean[] merged) { - if (plot.temp == -1 || dbManager == null) { + if (plot == null || merged == null) { return; } - DBFunc.dbManager.setMerged(plot, merged); + try { + PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + PlotSettingsRepository settingsRepo = PlotSquared.platform().injector().getInstance(PlotSettingsRepository.class); + String world = plot.getWorldName(); + int x = plot.getId().getX(); + int z = plot.getId().getY(); + Optional pe = plotRepo.findByWorldAndId(world, x, z); + pe.ifPresent(entity -> { + int mask = com.plotsquared.core.util.HashUtil.hash(merged); + settingsRepo.updateMerged(entity.getId(), mask); + }); + } catch (Throwable ignored) { + } } public static void setFlag(Plot plot, PlotFlag flag) { - if (plot.temp == -1 || dbManager == null) { + if (plot == null || flag == null) { return; } - DBFunc.dbManager.setFlag(plot, flag); + try { + PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + com.plotsquared.core.persistence.repository.api.PlotFlagRepository flagRepo = PlotSquared.platform().injector().getInstance(com.plotsquared.core.persistence.repository.api.PlotFlagRepository.class); + Optional pe = plotRepo.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); + pe.ifPresent(entity -> { + long plotId = entity.getId(); + String name = flag.getName(); + String value = flag.toString(); + var existing = flagRepo.findByPlotAndName(plotId, name); + if (existing.isPresent()) { + var e = existing.get(); + e.setValue(value); + flagRepo.save(e); + } else { + com.plotsquared.core.persistence.entity.PlotFlagEntity e = new com.plotsquared.core.persistence.entity.PlotFlagEntity(); + com.plotsquared.core.persistence.entity.PlotEntity pref = new com.plotsquared.core.persistence.entity.PlotEntity(); + pref.setId(entity.getId()); + e.setPlot(pref); + e.setFlag(name); + e.setValue(value); + flagRepo.save(e); + } + }); + } catch (Throwable ignored) { + } } public static void removeFlag(Plot plot, PlotFlag flag) { - if (plot.temp == -1 || dbManager == null) { + if (plot == null || flag == null) { return; } - DBFunc.dbManager.removeFlag(plot, flag); + try { + PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + com.plotsquared.core.persistence.repository.api.PlotFlagRepository flagRepo = PlotSquared.platform().injector().getInstance(com.plotsquared.core.persistence.repository.api.PlotFlagRepository.class); + Optional pe = plotRepo.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); + pe.ifPresent(entity -> flagRepo.deleteByPlotAndName(entity.getId(), flag.getName())); + } catch (Throwable ignored) { + } } /** @@ -333,24 +382,32 @@ public static void removeFlag(Plot plot, PlotFlag flag) { * @param alias */ public static void setAlias(Plot plot, String alias) { - if (plot.temp == -1 || dbManager == null) { + if (plot == null) { return; } - DBFunc.dbManager.setAlias(plot, alias); + try { + PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + PlotSettingsRepository settingsRepo = PlotSquared.platform().injector().getInstance(PlotSettingsRepository.class); + Optional pe = plotRepo.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); + pe.ifPresent(entity -> settingsRepo.updateAlias(entity.getId(), alias)); + } catch (Throwable ignored) { + } } public static void purgeIds(Set uniqueIds) { - if (dbManager == null) { - return; + try { + PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + plotRepo.purgeIds(uniqueIds); + } catch (Throwable ignored) { } - DBFunc.dbManager.purgeIds(uniqueIds); } public static void purge(PlotArea area, Set plotIds) { - if (dbManager == null) { - return; + try { + PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + plotRepo.purgeByWorldAndPlotIds(area.getWorldName(), plotIds); + } catch (Throwable ignored) { } - DBFunc.dbManager.purge(area, plotIds); } /** @@ -358,10 +415,16 @@ public static void purge(PlotArea area, Set plotIds) { * @param position */ public static void setPosition(Plot plot, String position) { - if (plot.temp == -1 || dbManager == null) { + if (plot == null || position == null) { return; } - DBFunc.dbManager.setPosition(plot, position); + try { + PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + PlotSettingsRepository settingsRepo = PlotSquared.platform().injector().getInstance(PlotSettingsRepository.class); + Optional pe = plotRepo.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); + pe.ifPresent(entity -> settingsRepo.updatePosition(entity.getId(), position)); + } catch (Throwable ignored) { + } } /** @@ -369,12 +432,9 @@ public static void setPosition(Plot plot, String position) { * @param comment */ public static void removeComment(Plot plot, PlotComment comment) { - if (plot.temp == -1) { - return; - } try { PlotCommentRepository repo = PlotSquared.platform().injector().getInstance(PlotCommentRepository.class); - String world = plot.getArea().toString(); + String world = plot.getWorldName(); int hash = plot.getId().hashCode(); repo.deleteOne(world, hash, comment.inbox(), comment.senderName(), comment.comment()); } catch (Throwable ignored) { @@ -382,13 +442,10 @@ public static void removeComment(Plot plot, PlotComment comment) { } public static void clearInbox(Plot plot, String inbox) { - if (plot != null && plot.temp == -1) { - return; - } try { PlotCommentRepository repo = PlotSquared.platform().injector().getInstance(PlotCommentRepository.class); if (plot != null) { - String world = plot.getArea().toString(); + String world = plot.getWorldName(); int hash = plot.getId().hashCode(); repo.clearInbox(world, hash, inbox); } else { @@ -403,14 +460,11 @@ public static void clearInbox(Plot plot, String inbox) { * @param comment */ public static void setComment(Plot plot, PlotComment comment) { - if (plot != null && plot.temp == -1) { - return; - } try { PlotCommentRepository repo = PlotSquared.platform().injector().getInstance(PlotCommentRepository.class); if (plot != null) { PlotCommentEntity entity = new PlotCommentEntity(); - entity.setWorld(plot.getArea().toString()); + entity.setWorld(plot.getWorldName()); entity.setHashcode(plot.getId().hashCode()); entity.setComment(comment.comment()); entity.setInbox(comment.inbox()); @@ -429,14 +483,11 @@ public static void getComments( Plot plot, String inbox, RunnableVal> whenDone ) { - if (plot != null && plot.temp == -1) { - return; - } try { PlotCommentRepository repo = PlotSquared.platform().injector().getInstance(PlotCommentRepository.class); List out = new java.util.ArrayList<>(); if (plot != null) { - String world = plot.getArea().toString(); + String world = plot.getWorldName(); int hash = plot.getId().hashCode(); for (PlotCommentEntity e : repo.findByWorldHashAndInbox(world, hash, inbox)) { PlotId id = (e.getHashcode() != null && e.getHashcode() != 0) ? PlotId.unpair(e.getHashcode()) : null; @@ -459,10 +510,21 @@ public static void getComments( * @param uuid */ public static void removeTrusted(Plot plot, UUID uuid) { - if (plot.temp == -1 || dbManager == null) { + if (plot == null) { return; } - DBFunc.dbManager.removeTrusted(plot, uuid); + try { + PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + PlotTrustedRepository trustedRepo = PlotSquared.platform().injector().getInstance(PlotTrustedRepository.class); + String world = plot.getArea().toString(); + int x = plot.getId().getX(); + int z = plot.getId().getY(); + java.util.Optional ent = plotRepo.findByWorldAndId(world, x, z); + if (ent.isPresent() && ent.get().getId() != null) { + trustedRepo.remove(ent.get().getId(), uuid.toString()); + } + } catch (Throwable ignored) { + } } /** @@ -470,20 +532,48 @@ public static void removeTrusted(Plot plot, UUID uuid) { * @param uuid */ public static void removeHelper(PlotCluster cluster, UUID uuid) { - if (dbManager == null) { + if (cluster == null || uuid == null) { return; } - DBFunc.dbManager.removeHelper(cluster, uuid); + try { + ClusterRepository clusterRepo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); + ClusterHelperRepository helperRepo = PlotSquared.platform().injector().getInstance(ClusterHelperRepository.class); + String world = cluster.area != null ? cluster.area.toString() : null; + PlotId center = cluster.getCenterPlotId(); + if (world != null) { + Optional ent = clusterRepo.findByWorldAndBounds(world, center.getX(), center.getY()); + if (ent.isPresent() && ent.get().getId() != null) { + helperRepo.remove(ent.get().getId(), uuid.toString()); + } + } + } catch (Throwable ignored) { + } } /** * @param cluster */ public static void createCluster(PlotCluster cluster) { - if (dbManager == null) { + if (cluster == null) { return; } - DBFunc.dbManager.createCluster(cluster); + try { + ClusterRepository repo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); + ClusterEntity e = new ClusterEntity(); + e.setWorld(cluster.area != null ? cluster.area.toString() : null); + e.setOwner(cluster.owner != null ? cluster.owner.toString() : null); + if (cluster.getP1() != null) { + e.setPos1X(cluster.getP1().getX()); + e.setPos1Z(cluster.getP1().getY()); + } + if (cluster.getP2() != null) { + e.setPos2X(cluster.getP2().getX()); + e.setPos2Z(cluster.getP2().getY()); + } + repo.save(e); + // Do not assign cluster.temp; avoid reassigning transient identifiers + } catch (Throwable ignored) { + } } /** @@ -492,10 +582,26 @@ public static void createCluster(PlotCluster cluster) { * @param max */ public static void resizeCluster(PlotCluster current, PlotId min, PlotId max) { - if (dbManager == null) { + if (current == null || min == null || max == null) { return; } - DBFunc.dbManager.resizeCluster(current, min, max); + try { + ClusterRepository repo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); + String world = current.area != null ? current.area.toString() : null; + PlotId center = current.getCenterPlotId(); + if (world != null) { + Optional ent = repo.findByWorldAndBounds(world, center.getX(), center.getY()); + if (ent.isPresent()) { + ClusterEntity e = ent.get(); + e.setPos1X(min.getX()); + e.setPos1Z(min.getY()); + e.setPos2X(max.getX()); + e.setPos2Z(max.getY()); + repo.save(e); + } + } + } catch (Throwable ignored) { + } } /** @@ -503,10 +609,12 @@ public static void resizeCluster(PlotCluster current, PlotId min, PlotId max) { * @param uuid */ public static void removeMember(Plot plot, UUID uuid) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.removeMember(plot, uuid); + PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + PlotMembershipRepository membershipRepo = PlotSquared.platform().injector().getInstance(PlotMembershipRepository.class); + String world = plot.getArea().toString(); + PlotId pid = plot.getId(); + Optional pe = plotRepo.findByWorldAndId(world, pid.getX(), pid.getY()); + pe.ifPresent(entity -> membershipRepo.remove(entity.getId(), uuid.toString())); } /** @@ -514,10 +622,15 @@ public static void removeMember(Plot plot, UUID uuid) { * @param uuid */ public static void removeInvited(PlotCluster cluster, UUID uuid) { - if (dbManager == null) { + ClusterRepository clusterRepo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); + ClusterInvitedRepository invitedRepo = PlotSquared.platform().injector().getInstance(ClusterInvitedRepository.class); + String world = cluster.area != null ? cluster.area.getWorldName() : null; + if (world == null) { return; } - DBFunc.dbManager.removeInvited(cluster, uuid); + PlotId center = cluster.getCenterPlotId(); + Optional ce = clusterRepo.findByWorldAndBounds(world, center.getX(), center.getY()); + ce.ifPresent(entity -> invitedRepo.remove(entity.getId(), uuid.toString())); } /** @@ -525,17 +638,24 @@ public static void removeInvited(PlotCluster cluster, UUID uuid) { * @param uuid */ public static void setTrusted(Plot plot, UUID uuid) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.setTrusted(plot, uuid); + PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + PlotTrustedRepository trustedRepo = PlotSquared.platform().injector().getInstance(PlotTrustedRepository.class); + String world = plot.getArea().toString(); + PlotId pid = plot.getId(); + Optional pe = plotRepo.findByWorldAndId(world, pid.getX(), pid.getY()); + pe.ifPresent(entity -> trustedRepo.add(entity.getId(), uuid.toString())); } public static void setHelper(PlotCluster cluster, UUID uuid) { - if (dbManager == null) { + ClusterRepository clusterRepo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); + ClusterHelperRepository helperRepo = PlotSquared.platform().injector().getInstance(ClusterHelperRepository.class); + String world = cluster.area != null ? cluster.area.getWorldName() : null; + if (world == null) { return; } - DBFunc.dbManager.setHelper(cluster, uuid); + PlotId center = cluster.getCenterPlotId(); + Optional ce = clusterRepo.findByWorldAndBounds(world, center.getX(), center.getY()); + ce.ifPresent(entity -> helperRepo.add(entity.getId(), uuid.toString())); } /** @@ -543,17 +663,24 @@ public static void setHelper(PlotCluster cluster, UUID uuid) { * @param uuid */ public static void setMember(Plot plot, UUID uuid) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.setMember(plot, uuid); + PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + PlotMembershipRepository membershipRepo = PlotSquared.platform().injector().getInstance(PlotMembershipRepository.class); + String world = plot.getArea().toString(); + PlotId pid = plot.getId(); + Optional pe = plotRepo.findByWorldAndId(world, pid.getX(), pid.getY()); + pe.ifPresent(entity -> membershipRepo.add(entity.getId(), uuid.toString())); } public static void setInvited(PlotCluster cluster, UUID uuid) { - if (dbManager == null) { + ClusterRepository clusterRepo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); + ClusterInvitedRepository invitedRepo = PlotSquared.platform().injector().getInstance(ClusterInvitedRepository.class); + String world = cluster.area != null ? cluster.area.getWorldName() : null; + if (world == null) { return; } - DBFunc.dbManager.setInvited(cluster, uuid); + PlotId center = cluster.getCenterPlotId(); + Optional ce = clusterRepo.findByWorldAndBounds(world, center.getX(), center.getY()); + ce.ifPresent(entity -> invitedRepo.add(entity.getId(), uuid.toString())); } /** @@ -561,10 +688,12 @@ public static void setInvited(PlotCluster cluster, UUID uuid) { * @param uuid */ public static void removeDenied(Plot plot, UUID uuid) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.removeDenied(plot, uuid); + PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + PlotDeniedRepository deniedRepo = PlotSquared.platform().injector().getInstance(PlotDeniedRepository.class); + String world = plot.getArea().toString(); + PlotId pid = plot.getId(); + Optional pe = plotRepo.findByWorldAndId(world, pid.getX(), pid.getY()); + pe.ifPresent(entity -> deniedRepo.remove(entity.getId(), uuid.toString())); } /** @@ -572,50 +701,132 @@ public static void removeDenied(Plot plot, UUID uuid) { * @param uuid */ public static void setDenied(Plot plot, UUID uuid) { - if (plot.temp == -1 || dbManager == null) { + if (plot == null || uuid == null) { return; } - DBFunc.dbManager.setDenied(plot, uuid); + try { + PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + PlotDeniedRepository deniedRepo = PlotSquared.platform().injector().getInstance(PlotDeniedRepository.class); + String world = plot.getArea().toString(); + PlotId pid = plot.getId(); + Optional pe = plotRepo.findByWorldAndId(world, pid.getX(), pid.getY()); + pe.ifPresent(entity -> deniedRepo.add(entity.getId(), uuid.toString())); + } catch (Throwable ignored) { + } } public static HashMap getRatings(Plot plot) { - if (plot.temp == -1 || dbManager == null) { + if (plot == null) { + return new HashMap<>(0); + } + try { + PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + com.plotsquared.core.persistence.repository.api.PlotRatingRepository ratingRepo = PlotSquared.platform().injector().getInstance(com.plotsquared.core.persistence.repository.api.PlotRatingRepository.class); + Optional pe = plotRepo.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); + HashMap out = new HashMap<>(); + pe.ifPresent(entity -> { + for (com.plotsquared.core.persistence.entity.PlotRatingEntity e : ratingRepo.findByPlotId(entity.getId())) { + try { + out.put(UUID.fromString(e.getPlayer()), e.getRating()); + } catch (IllegalArgumentException ignored) { + } + } + }); + return out; + } catch (Throwable ignored) { return new HashMap<>(0); } - return DBFunc.dbManager.getRatings(plot); } public static void setRating(Plot plot, UUID rater, int value) { - if (plot.temp == -1 || dbManager == null) { + if (plot == null || rater == null) { return; } - DBFunc.dbManager.setRating(plot, rater, value); + try { + PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + com.plotsquared.core.persistence.repository.api.PlotRatingRepository ratingRepo = PlotSquared.platform().injector().getInstance(com.plotsquared.core.persistence.repository.api.PlotRatingRepository.class); + Optional pe = plotRepo.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); + pe.ifPresent(entity -> ratingRepo.upsert(entity.getId(), rater.toString(), value)); + } catch (Throwable ignored) { + } } public static HashMap> getClusters() { - if (dbManager == null) { - return new HashMap<>(); + HashMap> result = new HashMap<>(); + try { + ClusterRepository clusterRepo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); + ClusterHelperRepository helperRepo = PlotSquared.platform().injector().getInstance(ClusterHelperRepository.class); + ClusterInvitedRepository invitedRepo = PlotSquared.platform().injector().getInstance(ClusterInvitedRepository.class); + ClusterSettingsRepository settingsRepo = PlotSquared.platform().injector().getInstance(ClusterSettingsRepository.class); + List clusters = clusterRepo.findAll(); + Map built = new HashMap<>(); + for (ClusterEntity ce : clusters) { + UUID owner = null; + try { owner = ce.getOwner() != null ? UUID.fromString(ce.getOwner()) : null; } catch (IllegalArgumentException ignored) {} + PlotCluster cluster = new PlotCluster(null, PlotId.of(ce.getPos1X(), ce.getPos1Z()), PlotId.of(ce.getPos2X(), ce.getPos2Z()), owner); + built.put(ce.getId(), cluster); + result.computeIfAbsent(ce.getWorld(), k -> new java.util.HashSet<>()).add(cluster); + } + // Populate helpers and invited + for (Map.Entry e : built.entrySet()) { + long id = e.getKey(); + PlotCluster cluster = e.getValue(); + for (String u : helperRepo.findUsers(id)) { + try { cluster.helpers.add(UUID.fromString(u)); } catch (IllegalArgumentException ignored) {} + } + for (String u : invitedRepo.findUsers(id)) { + try { cluster.invited.add(UUID.fromString(u)); } catch (IllegalArgumentException ignored) {} + } + // Apply settings (alias, merged). Avoid setting temp variable. + settingsRepo.findById(id).ifPresent(se -> { + if (se.getAlias() != null) { + cluster.settings.setAlias(se.getAlias()); + } + Integer m = se.getMerged(); + if (m != null) { + boolean[] merged = new boolean[4]; + for (int i = 0; i < 4; i++) { + merged[3 - i] = (m & 1 << i) != 0; + } + cluster.settings.setMerged(merged); + } + }); + } + } catch (Throwable ignored) { } - return DBFunc.dbManager.getClusters(); + return result; } public static void setPosition(PlotCluster cluster, String position) { - if (dbManager == null) { + if (cluster == null || position == null) { return; } - DBFunc.dbManager.setPosition(cluster, position); - } - - public static void replaceWorld(String oldWorld, String newWorld, PlotId min, PlotId max) { - if (dbManager == null) { - return; + try { + ClusterRepository clusterRepo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); + ClusterSettingsRepository settingsRepo = PlotSquared.platform().injector().getInstance(ClusterSettingsRepository.class); + String world = cluster.area != null ? cluster.area.getWorldName() : null; + if (world == null) { + return; + } + PlotId center = cluster.getCenterPlotId(); + java.util.Optional ce = clusterRepo.findByWorldAndBounds(world, center.getX(), center.getY()); + ce.ifPresent(entity -> settingsRepo.updatePosition(entity.getId(), position)); + } catch (Throwable ignored) { } - DBFunc.dbManager.replaceWorld(oldWorld, newWorld, min, max); } - public static void close() { - if (dbManager != null) { - DBFunc.dbManager.close(); + public static void replaceWorld(String oldWorld, String newWorld, PlotId min, PlotId max) { + try { + PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + ClusterRepository clusterRepo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); + if (min == null) { + plotRepo.replaceWorld(oldWorld, newWorld); + clusterRepo.replaceWorld(oldWorld, newWorld); + } else { + plotRepo.replaceWorldInBounds(oldWorld, newWorld, min, max); + clusterRepo.replaceWorldInBounds(oldWorld, newWorld, min, max); + } + } catch (Throwable ignored) { } } From 75a32448d98feeb39d37622ad2b86cf6fa5c2af4 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Thu, 4 Sep 2025 21:52:57 +0200 Subject: [PATCH 050/141] feat: remove legacy database classes and interfaces for a cleaner and modern architecture --- .../plotsquared/core/database/AbstractDB.java | 380 -- .../plotsquared/core/database/Database.java | 91 - .../com/plotsquared/core/database/MySQL.java | 119 - .../plotsquared/core/database/SQLManager.java | 3473 ----------------- .../com/plotsquared/core/database/SQLite.java | 120 - .../plotsquared/core/database/StmtMod.java | 57 - .../core/database/AbstractDBTest.java | 278 -- .../com/plotsquared/core/plot/FlagTest.java | 132 - 8 files changed, 4650 deletions(-) delete mode 100644 Core/src/main/java/com/plotsquared/core/database/AbstractDB.java delete mode 100644 Core/src/main/java/com/plotsquared/core/database/Database.java delete mode 100644 Core/src/main/java/com/plotsquared/core/database/MySQL.java delete mode 100644 Core/src/main/java/com/plotsquared/core/database/SQLManager.java delete mode 100644 Core/src/main/java/com/plotsquared/core/database/SQLite.java delete mode 100644 Core/src/main/java/com/plotsquared/core/database/StmtMod.java delete mode 100644 Core/src/test/java/com/plotsquared/core/database/AbstractDBTest.java delete mode 100644 Core/src/test/java/com/plotsquared/core/plot/FlagTest.java diff --git a/Core/src/main/java/com/plotsquared/core/database/AbstractDB.java b/Core/src/main/java/com/plotsquared/core/database/AbstractDB.java deleted file mode 100644 index 291772de90..0000000000 --- a/Core/src/main/java/com/plotsquared/core/database/AbstractDB.java +++ /dev/null @@ -1,380 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.core.database; - -import com.plotsquared.core.plot.Plot; -import com.plotsquared.core.plot.PlotArea; -import com.plotsquared.core.plot.PlotCluster; -import com.plotsquared.core.plot.PlotId; -import com.plotsquared.core.plot.comment.PlotComment; -import com.plotsquared.core.plot.flag.PlotFlag; -import com.plotsquared.core.util.task.RunnableVal; -import org.checkerframework.checker.nullness.qual.NonNull; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; - -public interface AbstractDB { - - /** - * The UUID that will count as EVERYONE. - */ - UUID everyone = UUID.fromString("1-1-3-3-7"); - - /** - * Sets Plot owner. - * - * @param plot the plot - * @param uuid the uuid of the new owner - */ - void setOwner(Plot plot, UUID uuid); - - /** - * Creates all settings, and create default helpers, trusted + denied lists. - * - * @param plots Plots for which the default table entries should be created - * @param whenDone the task to run when the method is finished executing - */ - void createPlotsAndData(List plots, Runnable whenDone); - - /** - * Creates a plot. - * - * @param plot the plot to create - */ - void createPlotSafe(final Plot plot, final Runnable success, final Runnable failure); - - /** - * Create tables. - * - * @throws Exception If the database manager is unable to create the tables - */ - void createTables() throws Exception; - - /** - * Deletes a plot. - * - * @param plot the plot to delete - */ - void delete(Plot plot); - - void deleteSettings(Plot plot); - - void deleteHelpers(Plot plot); - - void deleteTrusted(Plot plot); - - /** - * Removes all denied players from the plot. - * - * @param plot the plot - */ - void deleteDenied(Plot plot); - - /** - * Deletes all comments from the plot. - * - * @param plot the plot - */ - void deleteComments(Plot plot); - - void deleteRatings(Plot plot); - - void delete(PlotCluster cluster); - - void addPersistentMeta(UUID uuid, String key, byte[] meta, boolean delete); - - void removePersistentMeta(UUID uuid, String key); - - void getPersistentMeta(UUID uuid, RunnableVal> result); - - /** - * Creates the plot settings. - * - * @param id the plot entry id - * @param plot the plot - */ - void createPlotSettings(int id, Plot plot); - - /** - * Gets the table entry ID. - * - * @param plot the plot - * @return {@link Integer} = Plot Entry Id - */ - int getId(Plot plot); - - /** - * Gets the id of a given plot cluster. - * - * @param cluster PlotCluster Object - * @return Integer = Cluster Entry Id - */ - int getClusterId(PlotCluster cluster); - - boolean convertFlags(); - - /** - * @return A linked HashMap containing all plots - */ - HashMap> getPlots(); - - /** - * @param toValidate - */ - void validateAllPlots(Set toValidate); - - /** - * @return A HashMap containing all plot clusters - */ - HashMap> getClusters(); - - /** - * Sets the merged status for a plot. - * - * @param plot The plot to set the merged status of - * @param merged boolean[] - */ - void setMerged(Plot plot, boolean[] merged); - - /** - * Swaps the settings, helpers etc. of two plots. - * - * @param plot1 Plot1 - * @param plot2 Plot2 - */ - CompletableFuture swapPlots(Plot plot1, Plot plot2); - - /** - * Sets plot flag. - * - * @param plot Plot Object - * @param flag Flag to set - */ - void setFlag(Plot plot, PlotFlag flag); - - /** - * Remove a plot flag. - * - * @param plot Plot Object - * @param flag Flag to remove - */ - void removeFlag(Plot plot, PlotFlag flag); - - /** - * Renames a cluster to the given name. - * - * @param cluster the cluster to rename - * @param name the new cluster name - */ - void setClusterName(PlotCluster cluster, String name); - - /** - * Sets the plot alias. - * - * @param plot Plot for which the alias should be set - * @param alias Plot Alias - */ - void setAlias(Plot plot, String alias); - - /** - * Purges a plot. - * - * @param uniqueIds list of plot id (db) to be purged - */ - void purgeIds(Set uniqueIds); - - /** - * Purges a whole world. - * - * @param area World in which the plots should be purged - * @param plotIds the {@link PlotId}s of {@link Plot}s to purge - */ - void purge(PlotArea area, Set plotIds); - - /** - * Sets the plot home position. - * - * @param plot the plot - * @param position the position of plot home - */ - void setPosition(Plot plot, String position); - - /** - * @param cluster - * @param position - */ - void setPosition(PlotCluster cluster, String position); - - /** - * Remove the specified player from the trust list of the specified plot. - * - * @param plot the plot - * @param uuid the uuid of the player to remove - */ - void removeTrusted(Plot plot, UUID uuid); - - /** - * @param cluster PlotCluster Object - * @param uuid Player that should be removed - */ - void removeHelper(PlotCluster cluster, UUID uuid); - - /** - * @param plot the plot - * @param uuid Player that should be removed - */ - void removeMember(Plot plot, UUID uuid); - - /** - * @param cluster - * @param uuid - */ - void removeInvited(PlotCluster cluster, UUID uuid); - - /** - * @param plot Plot Object - * @param uuid Player that should be removed - */ - void setTrusted(Plot plot, UUID uuid); - - /** - * @param cluster PlotCluster Object - * @param uuid Player that should be removed - */ - void setHelper(PlotCluster cluster, UUID uuid); - - /** - * @param plot Plot Object - * @param uuid Player that should be added - */ - void setMember(Plot plot, UUID uuid); - - /** - * @param cluster - * @param uuid - */ - void setInvited(PlotCluster cluster, UUID uuid); - - /** - * Removes the specified player from the denied list of the specified plot. - * - * @param plot the plot - * @param uuid the uuid of the player to remove - */ - void removeDenied(Plot plot, UUID uuid); - - /** - * Denies the specified player from the given plot. - * - * @param plot the plot - * @param uuid the uuid of the player to deny - */ - void setDenied(Plot plot, UUID uuid); - - /** - * Gets the ratings from the specified plot. - * - * @param plot the plot - * @return the plot ratings (pre-calculated) - */ - HashMap getRatings(Plot plot); - - /** - * Sets a rating for a plot. - * - * @param plot - * @param rater - * @param value - */ - void setRating(Plot plot, UUID rater, int value); - - /** - * Removes the specified comment from the given plot. - * - * @param plot the plot - * @param comment the comment to remove - */ - void removeComment(Plot plot, PlotComment comment); - - /** - * Clears the specified inbox on the given plot. - * - * @param plot the plot - * @param inbox the inbox to clear - */ - void clearInbox(Plot plot, String inbox); - - /** - * Adds the specified comment to the given plot. - * - * @param plot the plot - * @param comment the comment to add - */ - void setComment(Plot plot, PlotComment comment); - - /** - * Gets Plot comments. - * - * @param plot The Plot to get comments from - */ - void getComments(@NonNull Plot plot, String inbox, RunnableVal> whenDone); - - void createPlotAndSettings(Plot plot, Runnable whenDone); - - void createCluster(PlotCluster cluster); - - void resizeCluster(PlotCluster current, PlotId min, PlotId max); - - void movePlot(Plot originalPlot, Plot newPlot); - - /** - * Replaces a old uuid with a new one in the database. - * - *
    - *
  • Useful for replacing a few uuids (not the entire database).
  • - *
  • or entire conversion, the uuidconvert command scales better.
  • - *
- * - * @param old - * @param now - */ - void replaceUUID(UUID old, UUID now); - - /** - * Don't use this method unless you want to ruin someone's server. - * - * @return {@code true} if the tables were deleted, {@code false} when an error is encountered - */ - boolean deleteTables(); - - /** - * Closes the database. Generally not recommended to be used by add-ons. - */ - void close(); - - void replaceWorld(String oldWorld, String newWorld, PlotId min, PlotId max); - - void updateTables(int[] oldVersion); - -} diff --git a/Core/src/main/java/com/plotsquared/core/database/Database.java b/Core/src/main/java/com/plotsquared/core/database/Database.java deleted file mode 100644 index 9f20ad7da6..0000000000 --- a/Core/src/main/java/com/plotsquared/core/database/Database.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.core.database; - -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -/** - * Abstract Database class, serves as a base for any connection method (MySQL, SQLite, etc.) - * - * @author -_Husky_- - * @author tips48 - */ -public abstract class Database { - - public abstract Connection forceConnection() throws SQLException, ClassNotFoundException; - - /** - * Opens a connection with the database. - * - * @return Opened connection - * @throws SQLException if the connection can not be opened - * @throws ClassNotFoundException if the driver cannot be found - */ - public abstract Connection openConnection() throws SQLException, ClassNotFoundException; - - /** - * Checks if a connection is open with the database. - * - * @return {@code true} if the connection is open - * @throws SQLException if the connection cannot be checked - */ - public abstract boolean checkConnection() throws SQLException; - - /** - * Gets the connection with the database. - * - * @return Connection with the database, null if none - */ - public abstract Connection getConnection(); - - /** - * Closes the connection with the database. - * - * @return {@code true} if successful - * @throws SQLException if the connection cannot be closed - */ - public abstract boolean closeConnection() throws SQLException; - - /** - * Executes a SQL Query. - * If the connection is closed, it will be opened. - * - * @param query Query to be run - * @return the results of the query - * @throws SQLException If the query cannot be executed - * @throws ClassNotFoundException If the driver cannot be found; see {@link #openConnection()} - */ - public abstract ResultSet querySQL(String query) throws SQLException, ClassNotFoundException; - - /** - * Executes an Update SQL Query. - * See {@link Statement#executeUpdate(String)}. - * If the connection is closed, it will be opened. - * - * @param query Query to be run - * @return Result Code, see {@link Statement#executeUpdate(String)} - * @throws SQLException If the query cannot be executed - * @throws ClassNotFoundException If the driver cannot be found; see {@link #openConnection()} - */ - public abstract int updateSQL(String query) throws SQLException, ClassNotFoundException; - -} diff --git a/Core/src/main/java/com/plotsquared/core/database/MySQL.java b/Core/src/main/java/com/plotsquared/core/database/MySQL.java deleted file mode 100644 index a8767b598c..0000000000 --- a/Core/src/main/java/com/plotsquared/core/database/MySQL.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.core.database; - -import com.plotsquared.core.configuration.Storage; -import com.plotsquared.core.util.StringMan; - -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -/** - * Connects to and uses a MySQL database - * - * @author -_Husky_- - * @author tips48 - */ -public class MySQL extends Database { - - private final String user; - private final String database; - private final String password; - private final String port; - private final String hostname; - private Connection connection; - - /** - * Creates a new MySQL instance. - * - * @param hostname Name of the host - * @param port Port number - * @param database Database name - * @param username Username - * @param password Password - */ - public MySQL(String hostname, String port, String database, String username, String password) { - this.hostname = hostname; - this.port = port; - this.database = database; - this.user = username; - this.password = password; - this.connection = null; - } - - @Override - public Connection forceConnection() throws SQLException { - this.connection = DriverManager.getConnection( - "jdbc:mysql://" + this.hostname + ':' + this.port + '/' + this.database + "?" - + StringMan.join(Storage.MySQL.PROPERTIES, "&"), this.user, this.password); - return this.connection; - } - - @Override - public Connection openConnection() throws SQLException { - if (checkConnection()) { - return this.connection; - } - return forceConnection(); - } - - @Override - public boolean checkConnection() throws SQLException { - return (this.connection != null) && !this.connection.isClosed(); - } - - @Override - public Connection getConnection() { - return this.connection; - } - - @Override - public boolean closeConnection() throws SQLException { - if (this.connection == null) { - return false; - } - this.connection.close(); - this.connection = null; - return true; - } - - @Override - public ResultSet querySQL(String query) throws SQLException { - if (checkConnection()) { - openConnection(); - } - try (Statement statement = this.connection.createStatement()) { - return statement.executeQuery(query); - } - } - - @Override - public int updateSQL(String query) throws SQLException { - if (checkConnection()) { - openConnection(); - } - try (Statement statement = this.connection.createStatement()) { - return statement.executeUpdate(query); - } - } - -} diff --git a/Core/src/main/java/com/plotsquared/core/database/SQLManager.java b/Core/src/main/java/com/plotsquared/core/database/SQLManager.java deleted file mode 100644 index 63d1af450c..0000000000 --- a/Core/src/main/java/com/plotsquared/core/database/SQLManager.java +++ /dev/null @@ -1,3473 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.core.database; - -import com.google.common.base.Charsets; -import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.configuration.ConfigurationSection; -import com.plotsquared.core.configuration.Settings; -import com.plotsquared.core.configuration.Storage; -import com.plotsquared.core.configuration.caption.CaptionUtility; -import com.plotsquared.core.configuration.file.YamlConfiguration; -import com.plotsquared.core.inject.annotations.WorldConfig; -import com.plotsquared.core.listener.PlotListener; -import com.plotsquared.core.location.BlockLoc; -import com.plotsquared.core.plot.Plot; -import com.plotsquared.core.plot.PlotArea; -import com.plotsquared.core.plot.PlotCluster; -import com.plotsquared.core.plot.PlotId; -import com.plotsquared.core.plot.PlotSettings; -import com.plotsquared.core.plot.comment.PlotComment; -import com.plotsquared.core.plot.flag.FlagContainer; -import com.plotsquared.core.plot.flag.FlagParseException; -import com.plotsquared.core.plot.flag.GlobalFlagContainer; -import com.plotsquared.core.plot.flag.PlotFlag; -import com.plotsquared.core.plot.flag.types.BlockTypeListFlag; -import com.plotsquared.core.util.EventDispatcher; -import com.plotsquared.core.util.HashUtil; -import com.plotsquared.core.util.StringMan; -import com.plotsquared.core.util.task.RunnableVal; -import com.plotsquared.core.util.task.TaskManager; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.checkerframework.checker.nullness.qual.NonNull; - -import java.sql.Connection; -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.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Queue; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.atomic.AtomicInteger; - - -@SuppressWarnings("SqlDialectInspection") -public class SQLManager implements AbstractDB { - - private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + SQLManager.class.getSimpleName()); - - // Public final - public final String SET_OWNER; - public final String GET_ALL_PLOTS; - public final String CREATE_PLOTS; - public final String CREATE_SETTINGS; - public final String CREATE_TIERS; - public final String CREATE_PLOT; - public final String CREATE_PLOT_SAFE; - public final String CREATE_CLUSTER; - - // Private Final - private final String prefix; - private final Database database; - private final boolean mySQL; - @SuppressWarnings({"unused", "FieldCanBeLocal"}) - private final EventDispatcher eventDispatcher; - @SuppressWarnings({"unused", "FieldCanBeLocal"}) - private final PlotListener plotListener; - private final YamlConfiguration worldConfiguration; - /** - * important tasks - */ - public volatile Queue globalTasks; - /** - * Notify tasks - */ - public volatile Queue notifyTasks; - /** - * plot - * plot_denied - * plot_helpers - * plot_trusted - * plot_comments - * plot_settings - * plot_rating - */ - public volatile ConcurrentHashMap> plotTasks; - /** - * player_meta - */ - public volatile ConcurrentHashMap> playerTasks; - /** - * cluster - * cluster_helpers - * cluster_invited - * cluster_settings - */ - public volatile ConcurrentHashMap> clusterTasks; - // Private - private Connection connection; - private boolean supportsGetGeneratedKeys; - private boolean closed = false; - - /** - * Constructor - * - * @param database - * @param prefix prefix - * @throws SQLException - * @throws ClassNotFoundException - */ - public SQLManager( - final @NonNull Database database, - final @NonNull String prefix, - final @NonNull EventDispatcher eventDispatcher, - final @NonNull PlotListener plotListener, - @WorldConfig final @NonNull YamlConfiguration worldConfiguration - ) - throws SQLException, ClassNotFoundException { - // Private final - this.eventDispatcher = eventDispatcher; - this.plotListener = plotListener; - this.worldConfiguration = worldConfiguration; - this.database = database; - this.connection = database.openConnection(); - final DatabaseMetaData databaseMetaData = this.connection.getMetaData(); - this.supportsGetGeneratedKeys = databaseMetaData.supportsGetGeneratedKeys(); - this.mySQL = database instanceof MySQL; - this.globalTasks = new ConcurrentLinkedQueue<>(); - this.notifyTasks = new ConcurrentLinkedQueue<>(); - this.plotTasks = new ConcurrentHashMap<>(); - this.playerTasks = new ConcurrentHashMap<>(); - this.clusterTasks = new ConcurrentHashMap<>(); - this.prefix = prefix; - - if (mySQL && !supportsGetGeneratedKeys) { - String driver = databaseMetaData.getDriverName(); - String driverVersion = databaseMetaData.getDriverVersion(); - throw new SQLException("Database Driver for MySQL does not support Statement#getGeneratedKeys - which breaks " + - "PlotSquared functionality (Using " + driver + ":" + driverVersion + ")"); - } - - this.SET_OWNER = "UPDATE `" + this.prefix - + "plot` SET `owner` = ? WHERE `plot_id_x` = ? AND `plot_id_z` = ? AND `world` = ?"; - this.GET_ALL_PLOTS = - "SELECT `id`, `plot_id_x`, `plot_id_z`, `world` FROM `" + this.prefix + "plot`"; - this.CREATE_PLOTS = "INSERT INTO `" + this.prefix - + "plot`(`plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp`) values "; - this.CREATE_SETTINGS = - "INSERT INTO `" + this.prefix + "plot_settings` (`plot_plot_id`) values "; - this.CREATE_TIERS = - "INSERT INTO `" + this.prefix + "plot_%tier%` (`plot_plot_id`, `user_uuid`) values "; - String tempCreatePlot = "INSERT INTO `" + this.prefix - + "plot`(`plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp`) VALUES(?, ?, ?, ?, ?)"; - if (!supportsGetGeneratedKeys) { - tempCreatePlot += " RETURNING `id`"; - } - this.CREATE_PLOT = tempCreatePlot; - if (mySQL) { - this.CREATE_PLOT_SAFE = "INSERT IGNORE INTO `" + this.prefix - + "plot`(`plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp`) SELECT ?, ?, ?, ?, ? FROM DUAL WHERE NOT EXISTS (SELECT null FROM `" - + this.prefix + "plot` WHERE `world` = ? AND `plot_id_x` = ? AND `plot_id_z` = ?)"; - } else { - String tempCreatePlotSafe = "INSERT INTO `" + this.prefix - + "plot`(`plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp`) SELECT ?, ?, ?, ?, ? WHERE NOT EXISTS (SELECT null FROM `" - + this.prefix + "plot` WHERE `world` = ? AND `plot_id_x` = ? AND `plot_id_z` = ?)"; - if (!supportsGetGeneratedKeys) { - tempCreatePlotSafe += " RETURNING `id`"; - } - this.CREATE_PLOT_SAFE = tempCreatePlotSafe; - } - String tempCreateCluster = "INSERT INTO `" + this.prefix - + "cluster`(`pos1_x`, `pos1_z`, `pos2_x`, `pos2_z`, `owner`, `world`) VALUES(?, ?, ?, ?, ?, ?)"; - if (!supportsGetGeneratedKeys) { - tempCreateCluster += " RETURNING `id`"; - } - this.CREATE_CLUSTER = tempCreateCluster; - - try { - createTables(); - } catch (SQLException e) { - e.printStackTrace(); - } - TaskManager.runTaskAsync(() -> { - long last = System.currentTimeMillis(); - while (!SQLManager.this.closed) { - boolean hasTask = - !globalTasks.isEmpty() || !playerTasks.isEmpty() || !plotTasks.isEmpty() - || !clusterTasks.isEmpty(); - if (hasTask) { - if (SQLManager.this.mySQL && System.currentTimeMillis() - last > 550000 - || !isValid()) { - last = System.currentTimeMillis(); - reconnect(); - } - if (!sendBatch()) { - try { - if (!getNotifyTasks().isEmpty()) { - for (Runnable task : getNotifyTasks()) { - TaskManager.runTask(task); - } - getNotifyTasks().clear(); - } - Thread.sleep(50); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } else { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - }); - } - - public boolean isValid() { - try { - if (connection.isClosed()) { - return false; - } - } catch (SQLException e) { - return false; - } - try (PreparedStatement stmt = this.connection.prepareStatement("SELECT 1")) { - stmt.execute(); - return true; - } catch (Throwable e) { - return false; - } - } - - public void reconnect() { - try { - close(); - SQLManager.this.closed = false; - SQLManager.this.connection = database.forceConnection(); - } catch (SQLException | ClassNotFoundException e) { - e.printStackTrace(); - } - } - - public synchronized Queue getGlobalTasks() { - return this.globalTasks; - } - - public synchronized Queue getNotifyTasks() { - return this.notifyTasks; - } - - public synchronized void addPlotTask(@NonNull Plot plot, UniqueStatement task) { - Queue tasks = this.plotTasks.get(plot); - if (tasks == null) { - tasks = new ConcurrentLinkedQueue<>(); - this.plotTasks.put(plot, tasks); - } - if (task == null) { - task = new UniqueStatement(String.valueOf(plot.hashCode())) { - - @Override - public PreparedStatement get() { - return null; - } - - @Override - public void set(PreparedStatement statement) { - } - - @Override - public void addBatch(PreparedStatement statement) { - } - - @Override - public void execute(PreparedStatement statement) { - } - - }; - } - tasks.add(task); - } - - public synchronized void addPlayerTask(UUID uuid, UniqueStatement task) { - if (uuid == null) { - return; - } - Queue tasks = this.playerTasks.get(uuid); - if (tasks == null) { - tasks = new ConcurrentLinkedQueue<>(); - this.playerTasks.put(uuid, tasks); - } - if (task == null) { - task = new UniqueStatement(String.valueOf(uuid.hashCode())) { - - @Override - public PreparedStatement get() { - return null; - } - - @Override - public void set(PreparedStatement statement) { - } - - @Override - public void addBatch(PreparedStatement statement) { - } - - @Override - public void execute(PreparedStatement statement) { - } - - }; - } - tasks.add(task); - } - - public synchronized void addClusterTask(PlotCluster cluster, UniqueStatement task) { - Queue tasks = this.clusterTasks.get(cluster); - if (tasks == null) { - tasks = new ConcurrentLinkedQueue<>(); - this.clusterTasks.put(cluster, tasks); - } - if (task == null) { - task = new UniqueStatement(String.valueOf(cluster.hashCode())) { - - @Override - public PreparedStatement get() { - return null; - } - - @Override - public void set(PreparedStatement statement) { - } - - @Override - public void addBatch(PreparedStatement statement) { - } - - @Override - public void execute(PreparedStatement statement) { - } - - }; - } - tasks.add(task); - } - - public synchronized void addGlobalTask(Runnable task) { - getGlobalTasks().add(task); - } - - public synchronized void addNotifyTask(Runnable task) { - if (task != null) { - getNotifyTasks().add(task); - } - } - - public boolean sendBatch() { - try { - if (!getGlobalTasks().isEmpty()) { - if (this.connection.getAutoCommit()) { - this.connection.setAutoCommit(false); - } - Runnable task = getGlobalTasks().remove(); - if (task != null) { - try { - task.run(); - } catch (Throwable e) { - LOGGER.error("============ DATABASE ERROR ============"); - LOGGER.error("============ DATABASE ERROR ============"); - LOGGER.error("There was an error updating the database."); - LOGGER.error(" - It will be corrected on shutdown"); - e.printStackTrace(); - LOGGER.error("========================================"); - } - } - commit(); - return true; - } - int count = -1; - if (!this.plotTasks.isEmpty()) { - count = Math.max(count, 0); - if (this.connection.getAutoCommit()) { - this.connection.setAutoCommit(false); - } - String method = null; - PreparedStatement statement = null; - UniqueStatement task = null; - UniqueStatement lastTask = null; - Iterator>> iterator = - this.plotTasks.entrySet().iterator(); - while (iterator.hasNext()) { - try { - Entry> entry = iterator.next(); - Queue tasks = entry.getValue(); - if (tasks.isEmpty()) { - iterator.remove(); - continue; - } - task = tasks.remove(); - count++; - if (task != null) { - if (task.method == null || !task.method.equals(method) - || statement == null) { - if (statement != null) { - lastTask.execute(statement); - statement.close(); - } - method = task.method; - statement = task.get(); - } - task.set(statement); - task.addBatch(statement); - try { - if (statement.isClosed()) { - statement = null; - } - } catch (NullPointerException | AbstractMethodError ignore) { - } - } - lastTask = task; - } catch (Throwable e) { - LOGGER.error("============ DATABASE ERROR ============"); - LOGGER.error("There was an error updating the database."); - LOGGER.error(" - It will be corrected on shutdown"); - LOGGER.error("========================================"); - e.printStackTrace(); - LOGGER.error("========================================"); - } - } - if (statement != null && task != null) { - task.execute(statement); - statement.close(); - } - } - if (!this.playerTasks.isEmpty()) { - count = Math.max(count, 0); - if (this.connection.getAutoCommit()) { - this.connection.setAutoCommit(false); - } - String method = null; - PreparedStatement statement = null; - UniqueStatement task = null; - UniqueStatement lastTask = null; - for (Entry> entry : this.playerTasks.entrySet()) { - try { - UUID uuid = entry.getKey(); - if (this.playerTasks.get(uuid).isEmpty()) { - this.playerTasks.remove(uuid); - continue; - } - task = this.playerTasks.get(uuid).remove(); - count++; - if (task != null) { - if (task.method == null || !task.method.equals(method)) { - if (statement != null) { - lastTask.execute(statement); - statement.close(); - } - method = task.method; - statement = task.get(); - } - task.set(statement); - task.addBatch(statement); - } - lastTask = task; - } catch (Throwable e) { - LOGGER.error("============ DATABASE ERROR ============"); - LOGGER.error("There was an error updating the database."); - LOGGER.error(" - It will be corrected on shutdown"); - LOGGER.error("========================================"); - e.printStackTrace(); - LOGGER.error("========================================"); - } - } - if (statement != null && task != null) { - task.execute(statement); - statement.close(); - } - } - if (!this.clusterTasks.isEmpty()) { - count = Math.max(count, 0); - if (this.connection.getAutoCommit()) { - this.connection.setAutoCommit(false); - } - String method = null; - PreparedStatement statement = null; - UniqueStatement task = null; - UniqueStatement lastTask = null; - for (Entry> entry : this.clusterTasks - .entrySet()) { - try { - PlotCluster cluster = entry.getKey(); - if (this.clusterTasks.get(cluster).isEmpty()) { - this.clusterTasks.remove(cluster); - continue; - } - task = this.clusterTasks.get(cluster).remove(); - count++; - if (task != null) { - if (task.method == null || !task.method.equals(method)) { - if (statement != null) { - lastTask.execute(statement); - statement.close(); - } - method = task.method; - statement = task.get(); - } - task.set(statement); - task.addBatch(statement); - } - lastTask = task; - } catch (Throwable e) { - LOGGER.error("============ DATABASE ERROR ============"); - LOGGER.error("There was an error updating the database."); - LOGGER.error(" - It will be corrected on shutdown"); - LOGGER.error("========================================"); - e.printStackTrace(); - LOGGER.error("========================================"); - } - } - if (statement != null && task != null) { - task.execute(statement); - statement.close(); - } - } - if (count > 0) { - commit(); - return true; - } - if (count != -1) { - if (!this.connection.getAutoCommit()) { - this.connection.setAutoCommit(true); - } - } - if (!this.clusterTasks.isEmpty()) { - this.clusterTasks.clear(); - } - if (!this.plotTasks.isEmpty()) { - this.plotTasks.clear(); - } - } catch (Throwable e) { - LOGGER.error("============ DATABASE ERROR ============"); - LOGGER.error("There was an error updating the database."); - LOGGER.error(" - It will be corrected on shutdown"); - LOGGER.error("========================================"); - e.printStackTrace(); - LOGGER.error("========================================"); - } - return false; - } - - public Connection getConnection() { - return this.connection; - } - - /** - * Set Plot owner - * - * @param plot Plot Object - * @param uuid Owner UUID - */ - @Override - public void setOwner(final Plot plot, final UUID uuid) { - addPlotTask(plot, new UniqueStatement("setOwner") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setString(1, uuid.toString()); - statement.setInt(2, plot.getId().getX()); - statement.setInt(3, plot.getId().getY()); - statement.setString(4, plot.getArea().toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement(SQLManager.this.SET_OWNER); - } - }); - } - - @Override - public void createPlotsAndData(final List myList, final Runnable whenDone) { - addGlobalTask(() -> { - try { - // Create the plots - createPlots(myList, () -> { - final Map idMap = new HashMap<>(); - - try { - // Creating datastructures - HashMap plotMap = new HashMap<>(); - for (Plot plot : myList) { - plotMap.put(plot.getId(), plot); - } - ArrayList settings = new ArrayList<>(); - final ArrayList helpers = new ArrayList<>(); - final ArrayList trusted = new ArrayList<>(); - final ArrayList denied = new ArrayList<>(); - - // Populating structures - try (PreparedStatement stmt = SQLManager.this.connection - .prepareStatement(SQLManager.this.GET_ALL_PLOTS); - ResultSet result = stmt.executeQuery()) { - while (result.next()) { - int id = result.getInt("id"); - int x = result.getInt("plot_id_x"); - int y = result.getInt("plot_id_z"); - PlotId plotId = PlotId.of(x, y); - Plot plot = plotMap.get(plotId); - idMap.put(plotId, id); - if (plot != null) { - settings.add(new LegacySettings(id, plot.getSettings())); - for (UUID uuid : plot.getDenied()) { - denied.add(new UUIDPair(id, uuid)); - } - for (UUID uuid : plot.getMembers()) { - trusted.add(new UUIDPair(id, uuid)); - } - for (UUID uuid : plot.getTrusted()) { - helpers.add(new UUIDPair(id, uuid)); - } - } - } - } - - createFlags(idMap, myList, () -> createSettings( - settings, - () -> createTiers(helpers, "helpers", - () -> createTiers(trusted, "trusted", - () -> createTiers(denied, "denied", () -> { - try { - SQLManager.this.connection.commit(); - } catch (SQLException e) { - e.printStackTrace(); - } - if (whenDone != null) { - whenDone.run(); - } - }) - ) - ) - )); - } catch (SQLException e) { - LOGGER.warn("Failed to set all flags and member tiers for plots", e); - try { - SQLManager.this.connection.commit(); - } catch (SQLException e1) { - e1.printStackTrace(); - } - } - }); - } catch (Exception e) { - LOGGER.warn("Warning! Failed to set all helper for plots", e); - try { - SQLManager.this.connection.commit(); - } catch (SQLException e1) { - e1.printStackTrace(); - } - } - }); - } - - /** - * Create a plot - * - * @param myList list of plots to be created - */ - public void createTiers(ArrayList myList, final String tier, Runnable whenDone) { - StmtMod mod = new StmtMod<>() { - @Override - public String getCreateMySQL(int size) { - return getCreateMySQL(size, SQLManager.this.CREATE_TIERS.replaceAll("%tier%", tier), - 2 - ); - } - - @Override - public String getCreateSQLite(int size) { - return getCreateSQLite(size, - "INSERT INTO `" + SQLManager.this.prefix + "plot_" + tier - + "` SELECT ? AS `plot_plot_id`, ? AS `user_uuid`", 2 - ); - } - - @Override - public String getCreateSQL() { - return "INSERT INTO `" + SQLManager.this.prefix + "plot_" + tier - + "` (`plot_plot_id`, `user_uuid`) VALUES(?,?)"; - } - - @Override - public void setMySQL(PreparedStatement stmt, int i, UUIDPair pair) - throws SQLException { - stmt.setInt(i * 2 + 1, pair.id); - stmt.setString(i * 2 + 2, pair.uuid.toString()); - } - - @Override - public void setSQLite(PreparedStatement stmt, int i, UUIDPair pair) - throws SQLException { - stmt.setInt(i * 2 + 1, pair.id); - stmt.setString(i * 2 + 2, pair.uuid.toString()); - } - - @Override - public void setSQL(PreparedStatement stmt, UUIDPair pair) - throws SQLException { - stmt.setInt(1, pair.id); - stmt.setString(2, pair.uuid.toString()); - } - }; - setBulk(myList, mod, whenDone); - } - - public void createFlags(Map ids, List plots, Runnable whenDone) { - try (final PreparedStatement preparedStatement = this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "plot_flags`(`plot_id`, `flag`, `value`) VALUES(?, ?, ?)")) { - for (final Plot plot : plots) { - final FlagContainer flagContainer = plot.getFlagContainer(); - for (final PlotFlag flagEntry : flagContainer.getFlagMap().values()) { - preparedStatement.setInt(1, ids.get(plot.getId())); - preparedStatement.setString(2, flagEntry.getName()); - preparedStatement.setString(3, flagEntry.toString()); - preparedStatement.addBatch(); - } - try { - preparedStatement.executeBatch(); - } catch (final Exception e) { - LOGGER.error("Failed to store flag values for plot with entry ID: {}", plot); - e.printStackTrace(); - continue; - } - LOGGER.info( - "- Finished converting flag values for plot with entry ID: {}", - plot.getId() - ); - } - } catch (final Exception e) { - LOGGER.error("Failed to store flag values", e); - } - LOGGER.info("Finished converting flags ({} plots processed)", plots.size()); - whenDone.run(); - } - - /** - * Create a plot - * - * @param myList list of plots to be created - */ - public void createPlots(List myList, Runnable whenDone) { - StmtMod mod = new StmtMod<>() { - @Override - public String getCreateMySQL(int size) { - return getCreateMySQL(size, SQLManager.this.CREATE_PLOTS, 5); - } - - @Override - public String getCreateSQLite(int size) { - return getCreateSQLite(size, "INSERT INTO `" + SQLManager.this.prefix - + "plot` SELECT ? AS `id`, ? AS `plot_id_x`, ? AS `plot_id_z`, ? AS `owner`, ? AS `world`, ? AS `timestamp` ", - 6 - ); - } - - @Override - public String getCreateSQL() { - return SQLManager.this.CREATE_PLOT; - } - - @Override - public void setMySQL(PreparedStatement stmt, int i, Plot plot) - throws SQLException { - stmt.setInt(i * 5 + 1, plot.getId().getX()); - stmt.setInt(i * 5 + 2, plot.getId().getY()); - try { - stmt.setString(i * 5 + 3, plot.getOwnerAbs().toString()); - } catch (SQLException ignored) { - stmt.setString(i * 5 + 3, everyone.toString()); - } - stmt.setString(i * 5 + 4, plot.getArea().toString()); - stmt.setTimestamp(i * 5 + 5, new Timestamp(plot.getTimestamp())); - } - - @Override - public void setSQLite(PreparedStatement stmt, int i, Plot plot) - throws SQLException { - stmt.setNull(i * 6 + 1, 4); - stmt.setInt(i * 6 + 2, plot.getId().getX()); - stmt.setInt(i * 6 + 3, plot.getId().getY()); - try { - stmt.setString(i * 6 + 4, plot.getOwnerAbs().toString()); - } catch (SQLException ignored) { - stmt.setString(i * 6 + 4, everyone.toString()); - } - stmt.setString(i * 6 + 5, plot.getArea().toString()); - stmt.setTimestamp(i * 6 + 6, new Timestamp(plot.getTimestamp())); - } - - @Override - public void setSQL(PreparedStatement stmt, Plot plot) throws SQLException { - stmt.setInt(1, plot.getId().getX()); - stmt.setInt(2, plot.getId().getY()); - stmt.setString(3, plot.getOwnerAbs().toString()); - stmt.setString(4, plot.getArea().toString()); - stmt.setTimestamp(5, new Timestamp(plot.getTimestamp())); - - } - }; - setBulk(myList, mod, whenDone); - } - - public void setBulk(List objList, StmtMod mod, Runnable whenDone) { - int size = objList.size(); - if (size == 0) { - if (whenDone != null) { - whenDone.run(); - } - return; - } - int packet; - if (this.mySQL) { - packet = Math.min(size, 5000); - } else { - packet = Math.min(size, 50); - } - int amount = size / packet; - try { - int count = 0; - PreparedStatement preparedStmt = null; - int last = -1; - for (int j = 0; j <= amount; j++) { - List subList = objList.subList(j * packet, Math.min(size, (j + 1) * packet)); - if (subList.isEmpty()) { - break; - } - String statement; - if (last == -1) { - last = subList.size(); - statement = mod.getCreateMySQL(subList.size()); - preparedStmt = this.connection.prepareStatement(statement); - } - if (subList.size() != last || count % 5000 == 0 && count > 0) { - preparedStmt.executeBatch(); - preparedStmt.close(); - statement = mod.getCreateMySQL(subList.size()); - preparedStmt = this.connection.prepareStatement(statement); - } - for (int i = 0; i < subList.size(); i++) { - count++; - T obj = subList.get(i); - mod.setMySQL(preparedStmt, i, obj); - } - last = subList.size(); - preparedStmt.addBatch(); - } - preparedStmt.executeBatch(); - preparedStmt.clearParameters(); - preparedStmt.close(); - if (whenDone != null) { - whenDone.run(); - } - return; - } catch (SQLException e) { - if (this.mySQL) { - LOGGER.error("1: | {}", objList.get(0).getClass().getCanonicalName()); - e.printStackTrace(); - } - } - try { - int count = 0; - PreparedStatement preparedStmt = null; - int last = -1; - for (int j = 0; j <= amount; j++) { - List subList = objList.subList(j * packet, Math.min(size, (j + 1) * packet)); - if (subList.isEmpty()) { - break; - } - String statement; - if (last == -1) { - last = subList.size(); - statement = mod.getCreateSQLite(subList.size()); - preparedStmt = this.connection.prepareStatement(statement); - } - if (subList.size() != last || count % 5000 == 0 && count > 0) { - preparedStmt.executeBatch(); - preparedStmt.clearParameters(); - statement = mod.getCreateSQLite(subList.size()); - preparedStmt = this.connection.prepareStatement(statement); - } - for (int i = 0; i < subList.size(); i++) { - count++; - T obj = subList.get(i); - mod.setSQLite(preparedStmt, i, obj); - } - last = subList.size(); - preparedStmt.addBatch(); - } - preparedStmt.executeBatch(); - preparedStmt.clearParameters(); - preparedStmt.close(); - } catch (SQLException e) { - e.printStackTrace(); - LOGGER.error("2: | {}", objList.get(0).getClass().getCanonicalName()); - LOGGER.error("Could not bulk save!"); - try (PreparedStatement preparedStmt = this.connection - .prepareStatement(mod.getCreateSQL())) { - for (T obj : objList) { - mod.setSQL(preparedStmt, obj); - preparedStmt.addBatch(); - } - preparedStmt.executeBatch(); - } catch (SQLException e3) { - LOGGER.error("Failed to save all", e); - e3.printStackTrace(); - } - } - if (whenDone != null) { - whenDone.run(); - } - } - - public void createSettings(final ArrayList myList, final Runnable whenDone) { - try (final PreparedStatement preparedStatement = this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix + "plot_settings`" - + "(`plot_plot_id`,`biome`,`rain`,`custom_time`,`time`,`deny_entry`,`alias`,`merged`,`position`) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)")) { - - int packet; - if (this.mySQL) { - packet = Math.min(myList.size(), 5000); - } else { - packet = Math.min(myList.size(), 50); - } - - int totalUpdated = 0; - int updated = 0; - - for (final LegacySettings legacySettings : myList) { - preparedStatement.setInt(1, legacySettings.id); - preparedStatement.setNull(2, 4); - preparedStatement.setNull(3, 4); - preparedStatement.setNull(4, 4); - preparedStatement.setNull(5, 4); - preparedStatement.setNull(6, 4); - if (legacySettings.settings.getAlias().isEmpty()) { - preparedStatement.setNull(7, 4); - } else { - preparedStatement.setString(7, legacySettings.settings.getAlias()); - } - boolean[] merged = legacySettings.settings.getMerged(); - int hash = HashUtil.hash(merged); - preparedStatement.setInt(8, hash); - BlockLoc loc = legacySettings.settings.getPosition(); - String position; - if (loc.getY() == 0) { - position = "DEFAULT"; - } else { - position = loc.getX() + "," + loc.getY() + ',' + loc.getZ(); - } - preparedStatement.setString(9, position); - preparedStatement.addBatch(); - if (++updated >= packet) { - try { - preparedStatement.executeBatch(); - } catch (final Exception e) { - LOGGER.error("Failed to store settings for plot with entry ID: {}", legacySettings.id); - e.printStackTrace(); - continue; - } - } - totalUpdated += 1; - } - - if (totalUpdated < myList.size()) { - try { - preparedStatement.executeBatch(); - } catch (final Exception e) { - LOGGER.error("Failed to store settings", e); - } - } - } catch (final Exception e) { - LOGGER.error("Failed to store settings", e); - } - LOGGER.info("Finished converting settings ({} plots processed)", myList.size()); - whenDone.run(); - } - - public void createEmptySettings(final ArrayList myList, final Runnable whenDone) { - final StmtMod mod = new StmtMod<>() { - @Override - public String getCreateMySQL(int size) { - return getCreateMySQL(size, SQLManager.this.CREATE_SETTINGS, 1); - } - - @Override - public String getCreateSQLite(int size) { - return getCreateSQLite(size, "INSERT INTO `" + SQLManager.this.prefix - + "plot_settings` SELECT ? AS `plot_plot_id`, ? AS `biome`, ? AS `rain`, ? AS `custom_time`, ? AS `time`, ? AS " - + "`deny_entry`, ? AS `alias`, ? AS `merged`, ? AS `position` ", 10); - } - - @Override - public String getCreateSQL() { - return "INSERT INTO `" + SQLManager.this.prefix - + "plot_settings`(`plot_plot_id`) VALUES(?)"; - } - - @Override - public void setMySQL(PreparedStatement stmt, int i, Integer id) - throws SQLException { - stmt.setInt(i + 1, id); - } - - @Override - public void setSQLite(PreparedStatement stmt, int i, Integer id) - throws SQLException { - stmt.setInt(i * 10 + 1, id); - stmt.setNull(i * 10 + 2, 4); - stmt.setNull(i * 10 + 3, 4); - stmt.setNull(i * 10 + 4, 4); - stmt.setNull(i * 10 + 5, 4); - stmt.setNull(i * 10 + 6, 4); - stmt.setNull(i * 10 + 7, 4); - stmt.setNull(i * 10 + 8, 4); - stmt.setString(i * 10 + 9, "DEFAULT"); - } - - @Override - public void setSQL(PreparedStatement stmt, Integer id) throws SQLException { - stmt.setInt(1, id); - } - }; - addGlobalTask(() -> setBulk(myList, mod, whenDone)); - } - - public void createPlotSafe(final Plot plot, final Runnable success, final Runnable failure) { - addPlotTask(plot, new UniqueStatement("createPlotSafe_" + plot.hashCode()) { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, plot.getId().getX()); - statement.setInt(2, plot.getId().getY()); - statement.setString(3, plot.getOwnerAbs().toString()); - statement.setString(4, plot.getArea().toString()); - statement.setTimestamp(5, new Timestamp(plot.getTimestamp())); - statement.setString(6, plot.getArea().toString()); - statement.setInt(7, plot.getId().getX()); - statement.setInt(8, plot.getId().getY()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - SQLManager.this.CREATE_PLOT_SAFE, - Statement.RETURN_GENERATED_KEYS - ); - } - - @Override - public void execute(PreparedStatement statement) { - - } - - @Override - public void addBatch(PreparedStatement statement) throws SQLException { - if (statement.execute() || statement.getUpdateCount() > 0) { - try (ResultSet keys = supportsGetGeneratedKeys ? statement.getGeneratedKeys() : statement.getResultSet()) { - if (keys.next()) { - plot.temp = keys.getInt(1); - addPlotTask(plot, new UniqueStatement( - "createPlotAndSettings_settings_" + plot.hashCode()) { - @Override - public void set(PreparedStatement statement) - throws SQLException { - statement.setInt(1, getId(plot)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "plot_settings`(`plot_plot_id`) VALUES(?)"); - } - }); - if (success != null) { - addNotifyTask(success); - } - return; - } - } - } - if (failure != null) { - failure.run(); - } - } - }); - } - - public void commit() { - if (this.closed) { - return; - } - try { - if (!this.connection.getAutoCommit()) { - this.connection.commit(); - this.connection.setAutoCommit(true); - } - } catch (SQLException e) { - e.printStackTrace(); - } - } - - @Override - public void createPlotAndSettings(final Plot plot, Runnable whenDone) { - addPlotTask(plot, new UniqueStatement("createPlotAndSettings_" + plot.hashCode()) { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, plot.getId().getX()); - statement.setInt(2, plot.getId().getY()); - statement.setString(3, plot.getOwnerAbs().toString()); - statement.setString(4, plot.getArea().toString()); - statement.setTimestamp(5, new Timestamp(plot.getTimestamp())); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection - .prepareStatement(SQLManager.this.CREATE_PLOT, Statement.RETURN_GENERATED_KEYS); - } - - @Override - public void execute(PreparedStatement statement) { - } - - @Override - public void addBatch(PreparedStatement statement) throws SQLException { - statement.execute(); - try (ResultSet keys = supportsGetGeneratedKeys ? statement.getGeneratedKeys() : statement.getResultSet()) { - if (keys.next()) { - plot.temp = keys.getInt(1); - } - } - } - }); - addPlotTask(plot, new UniqueStatement("createPlotAndSettings_settings_" + plot.hashCode()) { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "plot_settings`(`plot_plot_id`) VALUES(?)"); - } - }); - addNotifyTask(whenDone); - } - - /** - * Create tables. - * - * @throws SQLException - */ - @Override - public void createTables() throws SQLException { - String[] tables = - new String[]{"plot", "plot_denied", "plot_helpers", "plot_comments", "plot_trusted", - "plot_rating", "plot_settings", "cluster", "player_meta", "plot_flags"}; - DatabaseMetaData meta = this.connection.getMetaData(); - int create = 0; - for (String s : tables) { - ResultSet set = meta.getTables(null, null, this.prefix + s, new String[]{"TABLE"}); - // ResultSet set = meta.getTables(null, null, prefix + s, null); - if (!set.next()) { - create++; - } - set.close(); - } - if (create == 0) { - return; - } - boolean addConstraint = create == tables.length; - try (Statement stmt = this.connection.createStatement()) { - if (this.mySQL) { - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot` (" - + "`id` INT(11) NOT NULL AUTO_INCREMENT," + "`plot_id_x` INT(11) NOT NULL," - + "`plot_id_z` INT(11) NOT NULL," + "`owner` VARCHAR(40) NOT NULL," - + "`world` VARCHAR(45) NOT NULL," - + "`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP," - + "PRIMARY KEY (`id`)" - + ") ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=0"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix - + "plot_denied` (`plot_plot_id` INT(11) NOT NULL," - + "`user_uuid` VARCHAR(40) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_helpers` (" - + "`plot_plot_id` INT(11) NOT NULL," + "`user_uuid` VARCHAR(40) NOT NULL" - + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_comments` (" - + "`world` VARCHAR(40) NOT NULL, `hashcode` INT(11) NOT NULL," - + "`comment` VARCHAR(40) NOT NULL," + "`inbox` VARCHAR(40) NOT NULL," - + "`timestamp` INT(11) NOT NULL," + "`sender` VARCHAR(40) NOT NULL" - + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_trusted` (" - + "`plot_plot_id` INT(11) NOT NULL," + "`user_uuid` VARCHAR(40) NOT NULL" - + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_settings` (" - + " `plot_plot_id` INT(11) NOT NULL," - + " `biome` VARCHAR(45) DEFAULT 'FOREST'," + " `rain` INT(1) DEFAULT 0," - + " `custom_time` TINYINT(1) DEFAULT '0'," + " `time` INT(11) DEFAULT '8000'," - + " `deny_entry` TINYINT(1) DEFAULT '0'," - + " `alias` VARCHAR(50) DEFAULT NULL," + " `merged` INT(11) DEFAULT NULL," - + " `position` VARCHAR(50) NOT NULL DEFAULT 'DEFAULT'," - + " PRIMARY KEY (`plot_plot_id`)" + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix - + "plot_rating` ( `plot_plot_id` INT(11) NOT NULL, `rating` INT(2) NOT NULL, `player` VARCHAR(40) NOT NULL) ENGINE=InnoDB " - + "DEFAULT CHARSET=utf8"); - if (addConstraint) { - stmt.addBatch("ALTER TABLE `" + this.prefix + "plot_settings` ADD CONSTRAINT `" - + this.prefix - + "plot_settings_ibfk_1` FOREIGN KEY (`plot_plot_id`) REFERENCES `" - + this.prefix + "plot` (`id`) ON DELETE CASCADE"); - } - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster` (" - + "`id` INT(11) NOT NULL AUTO_INCREMENT," + "`pos1_x` INT(11) NOT NULL," - + "`pos1_z` INT(11) NOT NULL," + "`pos2_x` INT(11) NOT NULL," - + "`pos2_z` INT(11) NOT NULL," + "`owner` VARCHAR(40) NOT NULL," - + "`world` VARCHAR(45) NOT NULL," - + "`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP," - + "PRIMARY KEY (`id`)" - + ") ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=0"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster_helpers` (" - + "`cluster_id` INT(11) NOT NULL," + "`user_uuid` VARCHAR(40) NOT NULL" - + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster_invited` (" - + "`cluster_id` INT(11) NOT NULL," + "`user_uuid` VARCHAR(40) NOT NULL" - + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster_settings` (" - + " `cluster_id` INT(11) NOT NULL," + " `biome` VARCHAR(45) DEFAULT 'FOREST'," - + " `rain` INT(1) DEFAULT 0," + " `custom_time` TINYINT(1) DEFAULT '0'," - + " `time` INT(11) DEFAULT '8000'," + " `deny_entry` TINYINT(1) DEFAULT '0'," - + " `alias` VARCHAR(50) DEFAULT NULL," + " `merged` INT(11) DEFAULT NULL," - + " `position` VARCHAR(50) NOT NULL DEFAULT 'DEFAULT'," - + " PRIMARY KEY (`cluster_id`)" + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "player_meta` (" - + " `meta_id` INT(11) NOT NULL AUTO_INCREMENT," - + " `uuid` VARCHAR(40) NOT NULL," + " `key` VARCHAR(32) NOT NULL," - + " `value` blob NOT NULL," + " PRIMARY KEY (`meta_id`)" - + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_flags`(" - + "`id` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY," - + "`plot_id` INT(11) NOT NULL," + " `flag` VARCHAR(64)," - + " `value` VARCHAR(512)," + "FOREIGN KEY (plot_id) REFERENCES `" + this.prefix - + "plot` (id) ON DELETE CASCADE, " + "UNIQUE (plot_id, flag)" - + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); - } else { - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot` (" - + "`id` INTEGER PRIMARY KEY AUTOINCREMENT," + "`plot_id_x` INT(11) NOT NULL," - + "`plot_id_z` INT(11) NOT NULL," + "`owner` VARCHAR(45) NOT NULL," - + "`world` VARCHAR(45) NOT NULL," - + "`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP)"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix - + "plot_denied` (`plot_plot_id` INT(11) NOT NULL," - + "`user_uuid` VARCHAR(40) NOT NULL)"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix - + "plot_helpers` (`plot_plot_id` INT(11) NOT NULL," - + "`user_uuid` VARCHAR(40) NOT NULL)"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix - + "plot_trusted` (`plot_plot_id` INT(11) NOT NULL," - + "`user_uuid` VARCHAR(40) NOT NULL)"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_comments` (" - + "`world` VARCHAR(40) NOT NULL, `hashcode` INT(11) NOT NULL," - + "`comment` VARCHAR(40) NOT NULL," - + "`inbox` VARCHAR(40) NOT NULL, `timestamp` INT(11) NOT NULL," - + "`sender` VARCHAR(40) NOT NULL" + ')'); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_settings` (" - + " `plot_plot_id` INT(11) NOT NULL," - + " `biome` VARCHAR(45) DEFAULT 'FOREST'," + " `rain` INT(1) DEFAULT 0," - + " `custom_time` TINYINT(1) DEFAULT '0'," + " `time` INT(11) DEFAULT '8000'," - + " `deny_entry` TINYINT(1) DEFAULT '0'," - + " `alias` VARCHAR(50) DEFAULT NULL," + " `merged` INT(11) DEFAULT NULL," - + " `position` VARCHAR(50) NOT NULL DEFAULT 'DEFAULT'," - + " PRIMARY KEY (`plot_plot_id`)" + ')'); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix - + "plot_rating` (`plot_plot_id` INT(11) NOT NULL, `rating` INT(2) NOT NULL, `player` VARCHAR(40) NOT NULL)"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster` (" - + "`id` INTEGER PRIMARY KEY AUTOINCREMENT," + "`pos1_x` INT(11) NOT NULL," - + "`pos1_z` INT(11) NOT NULL," + "`pos2_x` INT(11) NOT NULL," - + "`pos2_z` INT(11) NOT NULL," + "`owner` VARCHAR(40) NOT NULL," - + "`world` VARCHAR(45) NOT NULL," - + "`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP" + ')'); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix - + "cluster_helpers` (`cluster_id` INT(11) NOT NULL," - + "`user_uuid` VARCHAR(40) NOT NULL)"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix - + "cluster_invited` (`cluster_id` INT(11) NOT NULL," - + "`user_uuid` VARCHAR(40) NOT NULL)"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster_settings` (" - + " `cluster_id` INT(11) NOT NULL," + " `biome` VARCHAR(45) DEFAULT 'FOREST'," - + " `rain` INT(1) DEFAULT 0," + " `custom_time` TINYINT(1) DEFAULT '0'," - + " `time` INT(11) DEFAULT '8000'," + " `deny_entry` TINYINT(1) DEFAULT '0'," - + " `alias` VARCHAR(50) DEFAULT NULL," + " `merged` INT(11) DEFAULT NULL," - + " `position` VARCHAR(50) NOT NULL DEFAULT 'DEFAULT'," - + " PRIMARY KEY (`cluster_id`)" + ')'); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "player_meta` (" - + " `meta_id` INTEGER PRIMARY KEY AUTOINCREMENT," - + " `uuid` VARCHAR(40) NOT NULL," + " `key` VARCHAR(32) NOT NULL," - + " `value` blob NOT NULL" + ')'); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_flags`(" - + "`id` INTEGER PRIMARY KEY AUTOINCREMENT," + "`plot_id` INTEGER NOT NULL," - + " `flag` VARCHAR(64)," + " `value` VARCHAR(512)," - + "FOREIGN KEY (plot_id) REFERENCES `" + this.prefix - + "plot` (id) ON DELETE CASCADE, " + "UNIQUE (plot_id, flag))"); - } - stmt.executeBatch(); - stmt.clearBatch(); - } - } - - @Override - public void deleteSettings(final Plot plot) { - addPlotTask(plot, new UniqueStatement("delete_plot_settings") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_settings` WHERE `plot_plot_id` = ?"); - } - }); - } - - @Override - public void deleteHelpers(final Plot plot) { - if (plot.getTrusted().isEmpty()) { - return; - } - addPlotTask(plot, new UniqueStatement("delete_plot_helpers") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_helpers` WHERE `plot_plot_id` = ?"); - } - }); - } - - @Override - public void deleteTrusted(final Plot plot) { - if (plot.getMembers().isEmpty()) { - return; - } - addPlotTask(plot, new UniqueStatement("delete_plot_trusted") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_trusted` WHERE `plot_plot_id` = ?"); - } - }); - } - - @Override - public void deleteDenied(final Plot plot) { - if (plot.getDenied().isEmpty()) { - return; - } - addPlotTask(plot, new UniqueStatement("delete_plot_denied") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_denied` WHERE `plot_plot_id` = ?"); - } - }); - } - - @Override - public void deleteComments(final Plot plot) { - addPlotTask(plot, new UniqueStatement("delete_plot_comments") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setString(1, plot.getArea().toString()); - statement.setInt(2, plot.hashCode()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_comments` WHERE `world` = ? AND `hashcode` = ?"); - } - }); - } - - @Override - public void deleteRatings(final Plot plot) { - if (Settings.Enabled_Components.RATING_CACHE && plot.getSettings().getRatings().isEmpty()) { - return; - } - addPlotTask(plot, new UniqueStatement("delete_plot_ratings") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_rating` WHERE `plot_plot_id` = ?"); - } - }); - } - - /** - * Delete a plot. - * - * @param plot - */ - @Override - public void delete(final Plot plot) { - deleteSettings(plot); - deleteDenied(plot); - deleteHelpers(plot); - deleteTrusted(plot); - deleteComments(plot); - deleteRatings(plot); - addPlotTask(plot, new UniqueStatement("delete_plot") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix + "plot` WHERE `id` = ?"); - } - }); - } - - /** - * Creates plot settings - * - * @param id - * @param plot - */ - @Override - public void createPlotSettings(final int id, Plot plot) { - addPlotTask(plot, new UniqueStatement("createPlotSettings") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, id); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "plot_settings`(`plot_plot_id`) VALUES(?)"); - } - }); - } - - @Override - public int getClusterId(PlotCluster cluster) { - if (cluster.temp > 0) { - return cluster.temp; - } - try { - commit(); - if (cluster.temp > 0) { - return cluster.temp; - } - int c_id; - try (PreparedStatement stmt = this.connection.prepareStatement( - "SELECT `id` FROM `" + this.prefix - + "cluster` WHERE `pos1_x` = ? AND `pos1_z` = ? AND `pos2_x` = ? AND `pos2_z` = ? AND `world` = ? ORDER BY `timestamp` ASC")) { - stmt.setInt(1, cluster.getP1().getX()); - stmt.setInt(2, cluster.getP1().getY()); - stmt.setInt(3, cluster.getP2().getX()); - stmt.setInt(4, cluster.getP2().getY()); - stmt.setString(5, cluster.area.toString()); - try (ResultSet resultSet = stmt.executeQuery()) { - c_id = Integer.MAX_VALUE; - while (resultSet.next()) { - c_id = resultSet.getInt("id"); - } - } - } - if (c_id == Integer.MAX_VALUE || c_id == 0) { - if (cluster.temp > 0) { - return cluster.temp; - } - throw new SQLException("Cluster does not exist in database"); - } - cluster.temp = c_id; - return c_id; - } catch (SQLException e) { - e.printStackTrace(); - } - return Integer.MAX_VALUE; - } - - @Override - public int getId(Plot plot) { - if (plot.temp > 0) { - return plot.temp; - } - try { - commit(); - if (plot.temp > 0) { - return plot.temp; - } - int id; - try (PreparedStatement statement = this.connection.prepareStatement( - "SELECT `id` FROM `" + this.prefix - + "plot` WHERE `plot_id_x` = ? AND `plot_id_z` = ? AND world = ? ORDER BY `timestamp` ASC")) { - statement.setInt(1, plot.getId().getX()); - statement.setInt(2, plot.getId().getY()); - statement.setString(3, plot.getArea().toString()); - try (ResultSet resultSet = statement.executeQuery()) { - id = Integer.MAX_VALUE; - while (resultSet.next()) { - id = resultSet.getInt("id"); - } - } - } - if (id == Integer.MAX_VALUE || id == 0) { - if (plot.temp > 0) { - return plot.temp; - } - throw new SQLException("Plot does not exist in database"); - } - plot.temp = id; - return id; - } catch (SQLException e) { - e.printStackTrace(); - } - return Integer.MAX_VALUE; - } - - @Override - public void updateTables(int[] oldVersion) { - try { - if (this.mySQL && !PlotSquared.get().checkVersion(oldVersion, 3, 3, 2)) { - try (Statement stmt = this.connection.createStatement()) { - stmt.executeUpdate( - "ALTER TABLE `" + this.prefix + "plots` DROP INDEX `unique_alias`"); - } catch (SQLException ignored) { - } - } - DatabaseMetaData data = this.connection.getMetaData(); - ResultSet rs = - data.getColumns(null, null, this.prefix + "plot_comments", "plot_plot_id"); - if (rs.next()) { - rs.close(); - rs = data.getColumns(null, null, this.prefix + "plot_comments", "hashcode"); - if (!rs.next()) { - rs.close(); - try (Statement statement = this.connection.createStatement()) { - statement.addBatch("DROP TABLE `" + this.prefix + "plot_comments`"); - if (Storage.MySQL.USE) { - statement.addBatch( - "CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_comments` (" - + "`world` VARCHAR(40) NOT NULL, `hashcode` INT(11) NOT NULL," - + "`comment` VARCHAR(40) NOT NULL," - + "`inbox` VARCHAR(40) NOT NULL," - + "`timestamp` INT(11) NOT NULL," - + "`sender` VARCHAR(40) NOT NULL" - + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); - } else { - statement.addBatch( - "CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_comments` (" - + "`world` VARCHAR(40) NOT NULL, `hashcode` INT(11) NOT NULL," - + "`comment` VARCHAR(40) NOT NULL," - + "`inbox` VARCHAR(40) NOT NULL, `timestamp` INT(11) NOT NULL," - + "`sender` VARCHAR(40) NOT NULL" + ')'); - } - statement.executeBatch(); - } catch (SQLException ignored) { - try (Statement statement = this.connection.createStatement()) { - statement.addBatch("ALTER IGNORE TABLE `" + this.prefix - + "plot_comments` ADD `inbox` VARCHAR(11) DEFAULT `public`"); - statement.addBatch("ALTER IGNORE TABLE `" + this.prefix - + "plot_comments` ADD `timestamp` INT(11) DEFAULT 0"); - statement.addBatch("ALTER TABLE `" + this.prefix + "plot` DROP `tier`"); - statement.executeBatch(); - } - } - } - } - rs.close(); - rs = data.getColumns(null, null, this.prefix + "plot_denied", "plot_plot_id"); - if (rs.next()) { - try (Statement statement = this.connection.createStatement()) { - statement.executeUpdate("DELETE FROM `" + this.prefix - + "plot_denied` WHERE `plot_plot_id` NOT IN (SELECT `id` FROM `" - + this.prefix + "plot`)"); - } catch (SQLException e) { - e.printStackTrace(); - } - - rs.close(); - try (Statement statement = this.connection.createStatement()) { - for (String table : new String[]{"plot_denied", "plot_helpers", - "plot_trusted"}) { - ResultSet result = statement.executeQuery( - "SELECT plot_plot_id, user_uuid, COUNT(*) FROM " + this.prefix + table - + " GROUP BY plot_plot_id, user_uuid HAVING COUNT(*) > 1"); - if (result.next()) { - result.close(); - statement.executeUpdate( - "CREATE TABLE " + this.prefix + table + "_tmp AS SELECT * FROM " - + this.prefix + table + " GROUP BY plot_plot_id, user_uuid"); - statement.executeUpdate("DROP TABLE " + this.prefix + table); - statement.executeUpdate( - "CREATE TABLE " + this.prefix + table + " AS SELECT * FROM " - + this.prefix + table + "_tmp"); - statement.executeUpdate("DROP TABLE " + this.prefix + table + "_tmp"); - } - } - } catch (SQLException e2) { - e2.printStackTrace(); - } - } - } catch (SQLException e) { - e.printStackTrace(); - } - - } - - public void deleteRows(ArrayList rowIds, final String table, final String column) { - setBulk(rowIds, new StmtMod<>() { - - @Override - public String getCreateMySQL(int size) { - return getCreateMySQL(1, "DELETE FROM `" + table + "` WHERE `" + column + "` IN ", - size - ); - } - - @Override - public String getCreateSQLite(int size) { - return getCreateMySQL(1, "DELETE FROM `" + table + "` WHERE `" + column + "` IN ", - size - ); - } - - @Override - public String getCreateSQL() { - return "DELETE FROM `" + table + "` WHERE `" + column + "` = ?"; - } - - @Override - public void setMySQL(PreparedStatement stmt, int i, Integer obj) - throws SQLException { - stmt.setInt(i + 1, obj); - } - - @Override - public void setSQLite(PreparedStatement stmt, int i, Integer obj) - throws SQLException { - stmt.setInt(i + 1, obj); - } - - @Override - public void setSQL(PreparedStatement stmt, Integer obj) throws SQLException { - stmt.setInt(1, obj); - } - }, null); - } - - @Override - public boolean convertFlags() { - final Map> flagMap = new HashMap<>(); - try (Statement statement = this.connection.createStatement()) { - try (ResultSet resultSet = statement - .executeQuery("SELECT * FROM `" + this.prefix + "plot_settings`")) { - while (resultSet.next()) { - final int id = resultSet.getInt("plot_plot_id"); - final String plotFlags = resultSet.getString("flags"); - if (plotFlags == null || plotFlags.isEmpty()) { - continue; - } - flagMap.put(id, new HashMap<>()); - for (String element : plotFlags.split(",")) { - if (element.contains(":")) { - String[] split = element.split(":"); // splits flag:value - try { - String flag_str = - split[1].replaceAll("¯", ":").replaceAll("\u00B4", ","); - flagMap.get(id).put(split[0], flag_str); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - } - } - } catch (final Exception e) { - LOGGER.error("Failed to load old flag values", e); - return false; - } - LOGGER.info("Loaded {} plot flag collections...", flagMap.size()); - LOGGER.info("Attempting to store these flags in the new table..."); - try (final PreparedStatement preparedStatement = this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "plot_flags`(`plot_id`, `flag`, `value`) VALUES(?, ?, ?)")) { - - long timeStarted = System.currentTimeMillis(); - int flagsProcessed = 0; - int plotsProcessed = 0; - - int totalFlags = 0; - for (final Map flags : flagMap.values()) { - totalFlags += flags.size(); - } - - for (final Map.Entry> plotFlagEntry : flagMap.entrySet()) { - for (final Map.Entry flagEntry : plotFlagEntry.getValue() - .entrySet()) { - preparedStatement.setInt(1, plotFlagEntry.getKey()); - preparedStatement.setString(2, flagEntry.getKey()); - preparedStatement.setString(3, flagEntry.getValue()); - preparedStatement.addBatch(); - flagsProcessed += 1; - } - plotsProcessed += 1; - - try { - preparedStatement.executeBatch(); - } catch (final Exception e) { - LOGGER.error("Failed to store flag values for plot with entry ID: {}", plotFlagEntry.getKey()); - e.printStackTrace(); - continue; - } - - if (System.currentTimeMillis() - timeStarted >= 1000L || plotsProcessed >= flagMap - .size()) { - timeStarted = System.currentTimeMillis(); - LOGGER.info( - "... Flag conversion in progress. {}% done", - String.format("%.1f", ((float) flagsProcessed / totalFlags) * 100) - ); - } - LOGGER.info( - "- Finished converting flags for plot with entry ID: {}", - plotFlagEntry.getKey() - ); - } - } catch (final Exception e) { - LOGGER.error("Failed to store flag values", e); - return false; - } - return true; - } - - /** - * Load all plots, helpers, denied, trusted, and every setting from DB into a {@link HashMap}. - */ - @Override - public HashMap> getPlots() { - HashMap> newPlots = new HashMap<>(); - HashMap plots = new HashMap<>(); - try { - HashSet areas = new HashSet<>(); - if (this.worldConfiguration.contains("worlds")) { - ConfigurationSection worldSection = this.worldConfiguration.getConfigurationSection("worlds"); - if (worldSection != null) { - for (String worldKey : worldSection.getKeys(false)) { - areas.add(worldKey); - ConfigurationSection areaSection = - worldSection.getConfigurationSection(worldKey + ".areas"); - if (areaSection != null) { - for (String areaKey : areaSection.getKeys(false)) { - String[] split = areaKey.split("(? uuids = new HashMap<>(); - HashMap noExist = new HashMap<>(); - - /* - * Getting plots - */ - try (Statement statement = this.connection.createStatement()) { - int id; - String o; - UUID user; - try (ResultSet resultSet = statement.executeQuery( - "SELECT `id`, `plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp` FROM `" - + this.prefix + "plot`")) { - ArrayList toDelete = new ArrayList<>(); - while (resultSet.next()) { - PlotId plot_id = PlotId.of( - resultSet.getInt("plot_id_x"), - resultSet.getInt("plot_id_z") - ); - id = resultSet.getInt("id"); - String areaID = resultSet.getString("world"); - if (!areas.contains(areaID)) { - if (Settings.Enabled_Components.DATABASE_PURGER) { - toDelete.add(id); - continue; - } else { - AtomicInteger value = noExist.get(areaID); - if (value != null) { - value.incrementAndGet(); - } else { - noExist.put(areaID, new AtomicInteger(1)); - } - } - } - o = resultSet.getString("owner"); - user = uuids.get(o); - if (user == null) { - try { - user = UUID.fromString(o); - } catch (IllegalArgumentException e) { - if (Settings.UUID.FORCE_LOWERCASE) { - user = UUID.nameUUIDFromBytes( - ("OfflinePlayer:" + o.toLowerCase()) - .getBytes(Charsets.UTF_8)); - } else { - user = UUID.nameUUIDFromBytes( - ("OfflinePlayer:" + o).getBytes(Charsets.UTF_8)); - } - } - uuids.put(o, user); - } - long time; - try { - Timestamp timestamp = resultSet.getTimestamp("timestamp"); - time = timestamp.getTime(); - } catch (SQLException exception) { - String parsable = resultSet.getString("timestamp"); - try { - time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(parsable) - .getTime(); - } catch (ParseException e) { - LOGGER.error("Could not parse date for plot: #{}({};{}) ({})", - id, areaID, plot_id, parsable - ); - time = System.currentTimeMillis() + id; - } - } - Plot p = new Plot(plot_id, user, new HashSet<>(), new HashSet<>(), - new HashSet<>(), "", null, null, null, - new boolean[]{false, false, false, false}, time, id - ); - HashMap map = newPlots.get(areaID); - if (map != null) { - Plot last = map.put(p.getId(), p); - if (last != null) { - if (Settings.Enabled_Components.DATABASE_PURGER) { - toDelete.add(last.temp); - } else { - LOGGER.info( - "Plot #{}({}) in `{}plot` is a duplicate." - + " Delete this plot or set `database-purger: true` in the settings.yml", - id, - last, - this.prefix - ); - } - } - } else { - map = new HashMap<>(); - newPlots.put(areaID, map); - map.put(p.getId(), p); - } - plots.put(id, p); - } - deleteRows(toDelete, this.prefix + "plot", "id"); - } - if (Settings.Enabled_Components.RATING_CACHE) { - try (ResultSet r = statement.executeQuery( - "SELECT `plot_plot_id`, `player`, `rating` FROM `" + this.prefix - + "plot_rating`")) { - ArrayList toDelete = new ArrayList<>(); - while (r.next()) { - id = r.getInt("plot_plot_id"); - o = r.getString("player"); - user = uuids.get(o); - if (user == null) { - user = UUID.fromString(o); - uuids.put(o, user); - } - Plot plot = plots.get(id); - if (plot != null) { - plot.getSettings().getRatings().put(user, r.getInt("rating")); - } else if (Settings.Enabled_Components.DATABASE_PURGER) { - toDelete.add(id); - } else { - LOGGER.warn("Entry #{}({}) in `plot_rating` does not exist." - + " Create this plot or set `database-purger: true` in settings.yml", id, plot); - } - } - deleteRows(toDelete, this.prefix + "plot_rating", "plot_plot_id"); - } - } - - /* - * Getting helpers - */ - try (ResultSet r = statement.executeQuery( - "SELECT `user_uuid`, `plot_plot_id` FROM `" + this.prefix + "plot_helpers`")) { - ArrayList toDelete = new ArrayList<>(); - while (r.next()) { - id = r.getInt("plot_plot_id"); - o = r.getString("user_uuid"); - user = uuids.get(o); - if (user == null) { - user = UUID.fromString(o); - uuids.put(o, user); - } - Plot plot = plots.get(id); - if (plot != null) { - plot.getTrusted().add(user); - } else if (Settings.Enabled_Components.DATABASE_PURGER) { - toDelete.add(id); - } else { - LOGGER.warn("Entry #{}({}) in `plot_helpers` does not exist." - + " Create this plot or set `database-purger: true` in settings.yml", id, plot); - } - } - deleteRows(toDelete, this.prefix + "plot_helpers", "plot_plot_id"); - } - - /* - * Getting trusted - */ - try (ResultSet r = statement.executeQuery( - "SELECT `user_uuid`, `plot_plot_id` FROM `" + this.prefix + "plot_trusted`")) { - ArrayList toDelete = new ArrayList<>(); - while (r.next()) { - id = r.getInt("plot_plot_id"); - o = r.getString("user_uuid"); - user = uuids.get(o); - if (user == null) { - user = UUID.fromString(o); - uuids.put(o, user); - } - Plot plot = plots.get(id); - if (plot != null) { - plot.getMembers().add(user); - } else if (Settings.Enabled_Components.DATABASE_PURGER) { - toDelete.add(id); - } else { - LOGGER.warn("Entry #{}({}) in `plot_trusted` does not exist." - + " Create this plot or set `database-purger: true` in settings.yml", id, plot); - } - } - deleteRows(toDelete, this.prefix + "plot_trusted", "plot_plot_id"); - } - - /* - * Getting denied - */ - try (ResultSet r = statement.executeQuery( - "SELECT `user_uuid`, `plot_plot_id` FROM `" + this.prefix + "plot_denied`")) { - ArrayList toDelete = new ArrayList<>(); - while (r.next()) { - id = r.getInt("plot_plot_id"); - o = r.getString("user_uuid"); - user = uuids.get(o); - if (user == null) { - user = UUID.fromString(o); - uuids.put(o, user); - } - Plot plot = plots.get(id); - if (plot != null) { - plot.getDenied().add(user); - } else if (Settings.Enabled_Components.DATABASE_PURGER) { - toDelete.add(id); - } else { - LOGGER.warn("Entry #{}({}) in `plot_denied` does not exist." - + " Create this plot or set `database-purger: true` in settings.yml", id, plot); - } - } - deleteRows(toDelete, this.prefix + "plot_denied", "plot_plot_id"); - } - - try (final ResultSet resultSet = statement - .executeQuery("SELECT * FROM `" + this.prefix + "plot_flags`")) { - BlockTypeListFlag.skipCategoryVerification = - true; // allow invalid tags, as initialized lazily - final ArrayList toDelete = new ArrayList<>(); - final Map>> invalidFlags = new HashMap<>(); - while (resultSet.next()) { - id = resultSet.getInt("plot_id"); - final String flag = resultSet.getString("flag"); - String value = resultSet.getString("value"); - final Plot plot = plots.get(id); - if (plot != null) { - final PlotFlag plotFlag = - GlobalFlagContainer.getInstance().getFlagFromString(flag); - if (plotFlag == null) { - plot.getFlagContainer().addUnknownFlag(flag, value); - } else { - value = CaptionUtility.stripClickEvents(plotFlag, value); - try { - plot.getFlagContainer().addFlag(plotFlag.parse(value)); - } catch (final FlagParseException e) { - e.printStackTrace(); - LOGGER.error("Plot with ID {} has an invalid value:", id); - LOGGER.error("Failed to parse flag '{}', value '{}': {}", - plotFlag.getName(), e.getValue(), e.getErrorMessage() - ); - if (!invalidFlags.containsKey(plot)) { - invalidFlags.put(plot, new ArrayList<>()); - } - invalidFlags.get(plot).add(plotFlag); - } - } - } else if (Settings.Enabled_Components.DATABASE_PURGER) { - toDelete.add(id); - } else { - LOGGER.warn("Entry #{}({}) in `plot_flags` does not exist." - + " Create this plot or set `database-purger: true` in settings.yml", id, plot); - } - } - BlockTypeListFlag.skipCategoryVerification = - false; // don't allow invalid tags anymore - if (Settings.Enabled_Components.DATABASE_PURGER) { - for (final Map.Entry>> plotFlagEntry : invalidFlags - .entrySet()) { - for (final PlotFlag flag : plotFlagEntry.getValue()) { - LOGGER.info( - "Plot {} has an invalid flag ({}). A fix has been attempted", - plotFlagEntry.getKey(), flag.getName() - ); - removeFlag(plotFlagEntry.getKey(), flag); - } - } - } - deleteRows(toDelete, this.prefix + "plot_flags", "plot_id"); - } - - try (ResultSet resultSet = statement - .executeQuery("SELECT * FROM `" + this.prefix + "plot_settings`")) { - ArrayList toDelete = new ArrayList<>(); - while (resultSet.next()) { - id = resultSet.getInt("plot_plot_id"); - Plot plot = plots.get(id); - if (plot != null) { - plots.remove(id); - String alias = resultSet.getString("alias"); - if (alias != null) { - plot.getSettings().setAlias(alias); - } - String pos = resultSet.getString("position"); - switch (pos.toLowerCase()) { - case "": - case "default": - case "0,0,0": - case "center": - case "centre": - break; - default: - try { - plot.getSettings().setPosition(BlockLoc.fromString(pos)); - } catch (Exception ignored) { - } - } - int m = resultSet.getInt("merged"); - boolean[] merged = new boolean[4]; - for (int i = 0; i < 4; i++) { - merged[3 - i] = (m & 1 << i) != 0; - } - plot.getSettings().setMerged(merged); - } else if (Settings.Enabled_Components.DATABASE_PURGER) { - toDelete.add(id); - } else { - LOGGER.warn("Entry #{}({}) in `plot_settings` does not exist." - + " Create this plot or set `database-purger: true` in settings.yml", id, plot); - } - } - deleteRows(toDelete, this.prefix + "plot_settings", "plot_plot_id"); - } - } - if (!plots.entrySet().isEmpty()) { - createEmptySettings(new ArrayList<>(plots.keySet()), null); - for (Entry entry : plots.entrySet()) { - entry.getValue().getSettings(); - } - } - boolean invalidPlot = false; - for (Entry entry : noExist.entrySet()) { - String worldName = entry.getKey(); - invalidPlot = true; - if (Settings.DEBUG) { - LOGGER.info("Warning! Found {} plots in DB for non existent world: '{}'", - entry.getValue().intValue(), worldName - ); - } - } - if (invalidPlot && Settings.DEBUG) { - LOGGER.info("Warning! Please create the world(s) or remove the plots using the purge command"); - } - } catch (SQLException e) { - LOGGER.error("Failed to load plots", e); - } - return newPlots; - } - - @Override - public void setMerged(final Plot plot, final boolean[] merged) { - plot.getSettings().setMerged(merged); - addPlotTask(plot, new UniqueStatement("setMerged") { - @Override - public void set(PreparedStatement statement) throws SQLException { - int hash = HashUtil.hash(merged); - statement.setInt(1, hash); - statement.setInt(2, getId(plot)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "plot_settings` SET `merged` = ? WHERE `plot_plot_id` = ?"); - } - }); - } - - @Override - public CompletableFuture swapPlots(Plot plot1, Plot plot2) { - final CompletableFuture future = new CompletableFuture<>(); - TaskManager.runTaskAsync(() -> { - final int id1 = getId(plot1); - final int id2 = getId(plot2); - final PlotId pos1 = plot1.getId(); - final PlotId pos2 = plot2.getId(); - try (final PreparedStatement preparedStatement = this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "plot` SET `plot_id_x` = ?, `plot_id_z` = ? WHERE `id` = ?")) { - preparedStatement.setInt(1, pos1.getX()); - preparedStatement.setInt(2, pos1.getY()); - preparedStatement.setInt(3, id1); - preparedStatement.execute(); - preparedStatement.setInt(1, pos2.getX()); - preparedStatement.setInt(2, pos2.getY()); - preparedStatement.setInt(3, id2); - preparedStatement.execute(); - } catch (final Exception e) { - LOGGER.error("Failed to persist wap of {} and {}", plot1, plot2); - e.printStackTrace(); - future.complete(false); - return; - } - future.complete(true); - }); - return future; - } - - @Override - public void movePlot(final Plot original, final Plot newPlot) { - addPlotTask(original, new UniqueStatement("movePlot") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, newPlot.getId().getX()); - statement.setInt(2, newPlot.getId().getY()); - statement.setString(3, newPlot.getArea().toString()); - statement.setInt(4, getId(original)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "plot` SET `plot_id_x` = ?, `plot_id_z` = ?, `world` = ? WHERE `id` = ?"); - } - }); - addPlotTask(newPlot, null); - } - - @Override - public void setFlag(final Plot plot, final PlotFlag flag) { - addPlotTask(plot, new UniqueStatement("setFlag") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - statement.setString(2, flag.getName()); - statement.setString(3, flag.toString()); - statement.setString(4, flag.toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - final String statement; - if (SQLManager.this.mySQL) { - statement = "INSERT INTO `" + SQLManager.this.prefix - + "plot_flags`(`plot_id`, `flag`, `value`) VALUES(?, ?, ?) " - + "ON DUPLICATE KEY UPDATE `value` = ?"; - } else { - statement = "INSERT INTO `" + SQLManager.this.prefix - + "plot_flags`(`plot_id`, `flag`, `value`) VALUES(?, ?, ?) " - + "ON CONFLICT(`plot_id`,`flag`) DO UPDATE SET `value` = ?"; - } - return SQLManager.this.connection.prepareStatement(statement); - } - }); - } - - @Override - public void removeFlag(final Plot plot, final PlotFlag flag) { - addPlotTask(plot, new UniqueStatement("removeFlag") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - statement.setString(2, flag.getName()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_flags` WHERE `plot_id` = ? AND `flag` = ?"); - } - }); - } - - @Override - public void setAlias(final Plot plot, final String alias) { - addPlotTask(plot, new UniqueStatement("setAlias") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setString(1, alias); - statement.setInt(2, getId(plot)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "plot_settings` SET `alias` = ? WHERE `plot_plot_id` = ?"); - } - }); - } - - /** - * Purge all plots with the following database IDs - */ - @Override - public void purgeIds(final Set uniqueIds) { - addGlobalTask(() -> { - if (!uniqueIds.isEmpty()) { - try { - ArrayList uniqueIdsList = new ArrayList<>(uniqueIds); - int size = uniqueIdsList.size(); - int packet = 990; - int amount = size / packet; - for (int j = 0; j <= amount; j++) { - List subList = - uniqueIdsList.subList(j * packet, Math.min(size, (j + 1) * packet)); - if (subList.isEmpty()) { - break; - } - StringBuilder idstr2 = new StringBuilder(); - String stmt_prefix = ""; - for (Integer id : subList) { - idstr2.append(stmt_prefix).append(id); - stmt_prefix = " OR `id` = "; - } - stmt_prefix = ""; - StringBuilder idstr = new StringBuilder(); - for (Integer id : subList) { - idstr.append(stmt_prefix).append(id); - stmt_prefix = " OR `plot_plot_id` = "; - } - PreparedStatement stmt = SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_helpers` WHERE `plot_plot_id` = " + idstr); - stmt.executeUpdate(); - stmt.close(); - stmt = SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_denied` WHERE `plot_plot_id` = " + idstr); - stmt.executeUpdate(); - stmt.close(); - stmt = SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_settings` WHERE `plot_plot_id` = " + idstr); - stmt.executeUpdate(); - stmt.close(); - stmt = SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_trusted` WHERE `plot_plot_id` = " + idstr); - stmt.executeUpdate(); - stmt.close(); - stmt = SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix + "plot` WHERE `id` = " - + idstr2); - stmt.executeUpdate(); - stmt.close(); - commit(); - } - } catch (SQLException e) { - LOGGER.error("Failed to purge plots", e); - return; - } - } - LOGGER.info("Successfully purged {} plots", uniqueIds.size()); - }); - } - - @Override - public void purge(final PlotArea area, final Set plots) { - addGlobalTask(() -> { - try (PreparedStatement stmt = SQLManager.this.connection.prepareStatement( - "SELECT `id`, `plot_id_x`, `plot_id_z` FROM `" + SQLManager.this.prefix - + "plot` WHERE `world` = ?")) { - stmt.setString(1, area.toString()); - Set ids; - try (ResultSet r = stmt.executeQuery()) { - ids = new HashSet<>(); - while (r.next()) { - PlotId plot_id = PlotId.of(r.getInt("plot_id_x"), r.getInt("plot_id_z")); - if (plots.contains(plot_id)) { - ids.add(r.getInt("id")); - } - } - } - purgeIds(ids); - } catch (SQLException e) { - LOGGER.error("Failed to purge area '{}'", area); - e.printStackTrace(); - } - for (Iterator iterator = plots.iterator(); iterator.hasNext(); ) { - PlotId plotId = iterator.next(); - iterator.remove(); - PlotId id = PlotId.of(plotId.getX(), plotId.getY()); - area.removePlot(id); - } - }); - } - - @Override - public void setPosition(final Plot plot, final String position) { - addPlotTask(plot, new UniqueStatement("setPosition") { - @Override - public void set(PreparedStatement statement) throws SQLException { - // Please see the table creation statement. There is the default value of "default" - statement.setString(1, position == null ? "DEFAULT" : position); - statement.setInt(2, getId(plot)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "plot_settings` SET `position` = ? WHERE `plot_plot_id` = ?"); - } - }); - } - - @Override - public void removeComment(final Plot plot, final PlotComment comment) { - addPlotTask(plot, new UniqueStatement("removeComment") { - @Override - public void set(PreparedStatement statement) throws SQLException { - if (plot != null) { - statement.setString(1, plot.getArea().toString()); - statement.setInt(2, plot.getId().hashCode()); - statement.setString(3, comment.comment()); - statement.setString(4, comment.inbox()); - statement.setString(5, comment.senderName()); - } else { - statement.setString(1, comment.comment()); - statement.setString(2, comment.inbox()); - statement.setString(3, comment.senderName()); - } - } - - @Override - public PreparedStatement get() throws SQLException { - if (plot != null) { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_comments` WHERE `world` = ? AND `hashcode` = ? AND `comment` = ? AND `inbox` = ? AND `sender` = ?"); - } - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_comments` WHERE `comment` = ? AND `inbox` = ? AND `sender` = ?"); - } - }); - } - - @Override - public void clearInbox(final Plot plot, final String inbox) { - addPlotTask(plot, new UniqueStatement("clearInbox") { - @Override - public void set(PreparedStatement statement) throws SQLException { - if (plot != null) { - statement.setString(1, plot.getArea().toString()); - statement.setInt(2, plot.getId().hashCode()); - statement.setString(3, inbox); - } else { - statement.setString(1, inbox); - } - } - - @Override - public PreparedStatement get() throws SQLException { - if (plot != null) { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_comments` WHERE `world` = ? AND `hashcode` = ? AND `inbox` = ?"); - } - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix + "plot_comments` `inbox` = ?"); - } - }); - } - - @Override - public void getComments( - @NonNull Plot plot, final String inbox, - final RunnableVal> whenDone - ) { - addPlotTask(plot, new UniqueStatement("getComments_" + plot) { - @Override - public void set(PreparedStatement statement) throws SQLException { - if (plot != null) { - statement.setString(1, plot.getArea().toString()); - statement.setInt(2, plot.getId().hashCode()); - statement.setString(3, inbox); - } else { - statement.setString(1, inbox); - } - } - - @Override - public PreparedStatement get() throws SQLException { - if (plot != null) { - return SQLManager.this.connection.prepareStatement( - "SELECT * FROM `" + SQLManager.this.prefix - + "plot_comments` WHERE `world` = ? AND `hashcode` = ? AND `inbox` = ?"); - } - return SQLManager.this.connection.prepareStatement( - "SELECT * FROM `" + SQLManager.this.prefix - + "plot_comments` WHERE `inbox` = ?"); - } - - @Override - public void execute(PreparedStatement statement) { - } - - @Override - public void addBatch(PreparedStatement statement) throws SQLException { - ArrayList comments = new ArrayList<>(); - try (ResultSet set = statement.executeQuery()) { - while (set.next()) { - String sender = set.getString("sender"); - String world = set.getString("world"); - int hash = set.getInt("hashcode"); - PlotId id; - if (hash != 0) { - id = PlotId.unpair(hash); - } else { - id = null; - } - String msg = set.getString("comment"); - long timestamp = set.getInt("timestamp") * 1000; - PlotComment comment = - new PlotComment(world, id, msg, sender, inbox, timestamp); - comments.add(comment); - } - whenDone.value = comments; - } - TaskManager.runTask(whenDone); - } - }); - } - - @Override - public void setComment(final Plot plot, final PlotComment comment) { - addPlotTask(plot, new UniqueStatement("setComment") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setString(1, plot.getArea().toString()); - statement.setInt(2, plot.getId().hashCode()); - statement.setString(3, comment.comment()); - statement.setString(4, comment.inbox()); - statement.setInt(5, (int) (comment.timestamp() / 1000)); - statement.setString(6, comment.senderName()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "plot_comments` (`world`, `hashcode`, `comment`, `inbox`, `timestamp`, `sender`) VALUES(?,?,?,?,?,?)"); - } - }); - } - - @Override - public void removeTrusted(final Plot plot, final UUID uuid) { - addPlotTask(plot, new UniqueStatement("removeTrusted") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - statement.setString(2, uuid.toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_helpers` WHERE `plot_plot_id` = ? AND `user_uuid` = ?"); - } - }); - } - - @Override - public void removeMember(final Plot plot, final UUID uuid) { - addPlotTask(plot, new UniqueStatement("removeMember") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - statement.setString(2, uuid.toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_trusted` WHERE `plot_plot_id` = ? AND `user_uuid` = ?"); - } - }); - } - - @Override - public void setTrusted(final Plot plot, final UUID uuid) { - addPlotTask(plot, new UniqueStatement("setTrusted") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - statement.setString(2, uuid.toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "plot_helpers` (`plot_plot_id`, `user_uuid`) VALUES(?,?)"); - } - }); - } - - @Override - public void setMember(final Plot plot, final UUID uuid) { - addPlotTask(plot, new UniqueStatement("setMember") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - statement.setString(2, uuid.toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "plot_trusted` (`plot_plot_id`, `user_uuid`) VALUES(?,?)"); - } - }); - } - - @Override - public void removeDenied(final Plot plot, final UUID uuid) { - addPlotTask(plot, new UniqueStatement("removeDenied") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - statement.setString(2, uuid.toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_denied` WHERE `plot_plot_id` = ? AND `user_uuid` = ?"); - } - }); - } - - @Override - public void setDenied(final Plot plot, final UUID uuid) { - addPlotTask(plot, new UniqueStatement("setDenied") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - statement.setString(2, uuid.toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "plot_denied` (`plot_plot_id`, `user_uuid`) VALUES(?,?)"); - } - }); - } - - @Override - public HashMap getRatings(Plot plot) { - HashMap map = new HashMap<>(); - try (PreparedStatement statement = this.connection.prepareStatement( - "SELECT `rating`, `player` FROM `" + this.prefix - + "plot_rating` WHERE `plot_plot_id` = ? ")) { - statement.setInt(1, getId(plot)); - try (ResultSet resultSet = statement.executeQuery()) { - while (resultSet.next()) { - UUID uuid = UUID.fromString(resultSet.getString("player")); - int rating = resultSet.getInt("rating"); - map.put(uuid, rating); - } - } - } catch (SQLException e) { - LOGGER.error("Failed to fetch rating for plot {}", plot.getId().toString()); - e.printStackTrace(); - } - return map; - } - - @Override - public void setRating(final Plot plot, final UUID rater, final int value) { - addPlotTask(plot, new UniqueStatement("setRating") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - statement.setInt(2, value); - statement.setString(3, rater.toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "plot_rating` (`plot_plot_id`, `rating`, `player`) VALUES(?,?,?)"); - } - }); - } - - @Override - public void delete(PlotCluster cluster) { - final int id = getClusterId(cluster); - addClusterTask(cluster, new UniqueStatement("delete_cluster_settings") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, id); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "cluster_settings` WHERE `cluster_id` = ?"); - } - }); - addClusterTask(cluster, new UniqueStatement("delete_cluster_helpers") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, id); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "cluster_helpers` WHERE `cluster_id` = ?"); - } - }); - addClusterTask(cluster, new UniqueStatement("delete_cluster_invited") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, id); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "cluster_invited` WHERE `cluster_id` = ?"); - } - }); - addClusterTask(cluster, new UniqueStatement("delete_cluster") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, id); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix + "cluster` WHERE `id` = ?"); - } - }); - } - - @Override - public void addPersistentMeta( - final UUID uuid, final String key, final byte[] meta, - final boolean replace - ) { - addPlayerTask(uuid, new UniqueStatement("addPersistentMeta") { - @Override - public void set(PreparedStatement statement) throws SQLException { - if (replace) { - statement.setBytes(1, meta); - statement.setString(2, uuid.toString()); - statement.setString(3, key); - } else { - statement.setString(1, uuid.toString()); - statement.setString(2, key); - statement.setBytes(3, meta); - } - } - - @Override - public PreparedStatement get() throws SQLException { - if (replace) { - return SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "player_meta` SET `value` = ? WHERE `uuid` = ? AND `key` = ?"); - } else { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "player_meta`(`uuid`, `key`, `value`) VALUES(?, ? ,?)"); - } - } - }); - } - - @Override - public void removePersistentMeta(final UUID uuid, final String key) { - addPlayerTask(uuid, new UniqueStatement("removePersistentMeta") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setString(1, uuid.toString()); - statement.setString(2, key); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "player_meta` WHERE `uuid` = ? AND `key` = ?"); - } - }); - } - - @Override - public void getPersistentMeta(final UUID uuid, final RunnableVal> result) { - addPlayerTask(uuid, new UniqueStatement("getPersistentMeta") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setString(1, uuid.toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "SELECT * FROM `" + SQLManager.this.prefix - + "player_meta` WHERE `uuid` = ? ORDER BY `meta_id` ASC"); - } - - @Override - public void execute(PreparedStatement statement) { - } - - @Override - public void addBatch(PreparedStatement statement) throws SQLException { - ResultSet resultSet = statement.executeQuery(); - - final Map metaMap = new HashMap<>(); - - while (resultSet.next()) { - String key = resultSet.getString("key"); - byte[] bytes = resultSet.getBytes("value"); - metaMap.put(key, bytes); - } - - resultSet.close(); - TaskManager.runTaskAsync(() -> result.run(metaMap)); - } - - }); - } - - @Override - public HashMap> getClusters() { - LinkedHashMap> newClusters = new LinkedHashMap<>(); - HashMap clusters = new HashMap<>(); - try { - HashSet areas = new HashSet<>(); - if (this.worldConfiguration.contains("worlds")) { - ConfigurationSection worldSection = this.worldConfiguration.getConfigurationSection("worlds"); - if (worldSection != null) { - for (String worldKey : worldSection.getKeys(false)) { - areas.add(worldKey); - ConfigurationSection areaSection = - worldSection.getConfigurationSection(worldKey + ".areas"); - if (areaSection != null) { - for (String areaKey : areaSection.getKeys(false)) { - String[] split = areaKey.split("(? uuids = new HashMap<>(); - HashMap noExist = new HashMap<>(); - /* - * Getting clusters - */ - try (Statement stmt = this.connection.createStatement()) { - ResultSet resultSet = - stmt.executeQuery("SELECT * FROM `" + this.prefix + "cluster`"); - PlotCluster cluster; - String owner; - UUID user; - int id; - while (resultSet.next()) { - PlotId pos1 = - PlotId.of(resultSet.getInt("pos1_x"), resultSet.getInt("pos1_z")); - PlotId pos2 = - PlotId.of(resultSet.getInt("pos2_x"), resultSet.getInt("pos2_z")); - id = resultSet.getInt("id"); - String areaid = resultSet.getString("world"); - if (!areas.contains(areaid)) { - noExist.merge(areaid, 1, Integer::sum); - } - owner = resultSet.getString("owner"); - user = uuids.get(owner); - if (user == null) { - user = UUID.fromString(owner); - uuids.put(owner, user); - } - cluster = new PlotCluster(null, pos1, pos2, user, id); - clusters.put(id, cluster); - Set set = - newClusters.computeIfAbsent(areaid, k -> new HashSet<>()); - set.add(cluster); - } - //Getting helpers - resultSet = stmt.executeQuery( - "SELECT `user_uuid`, `cluster_id` FROM `" + this.prefix + "cluster_helpers`"); - while (resultSet.next()) { - id = resultSet.getInt("cluster_id"); - owner = resultSet.getString("user_uuid"); - user = uuids.get(owner); - if (user == null) { - user = UUID.fromString(owner); - uuids.put(owner, user); - } - cluster = clusters.get(id); - if (cluster != null) { - cluster.helpers.add(user); - } else { - LOGGER.warn("Cluster #{}({}) in cluster_helpers does not exist." - + " Please create the cluster or remove this entry", id, cluster); - } - } - // Getting invited - resultSet = stmt.executeQuery( - "SELECT `user_uuid`, `cluster_id` FROM `" + this.prefix + "cluster_invited`"); - while (resultSet.next()) { - id = resultSet.getInt("cluster_id"); - owner = resultSet.getString("user_uuid"); - user = uuids.get(owner); - if (user == null) { - user = UUID.fromString(owner); - uuids.put(owner, user); - } - cluster = clusters.get(id); - if (cluster != null) { - cluster.invited.add(user); - } else { - LOGGER.warn("Cluster #{}({}) in cluster_helpers does not exist." - + " Please create the cluster or remove this entry", id, cluster); - } - } - resultSet = - stmt.executeQuery("SELECT * FROM `" + this.prefix + "cluster_settings`"); - while (resultSet.next()) { - id = resultSet.getInt("cluster_id"); - cluster = clusters.get(id); - if (cluster != null) { - String alias = resultSet.getString("alias"); - if (alias != null) { - cluster.settings.setAlias(alias); - } - String pos = resultSet.getString("position"); - switch (pos.toLowerCase()) { - case "": - case "default": - case "0,0,0": - case "center": - case "centre": - break; - default: - try { - BlockLoc loc = BlockLoc.fromString(pos); - cluster.settings.setPosition(loc); - } catch (Exception ignored) { - } - } - int m = resultSet.getInt("merged"); - boolean[] merged = new boolean[4]; - for (int i = 0; i < 4; i++) { - merged[3 - i] = (m & 1 << i) != 0; - } - cluster.settings.setMerged(merged); - } else { - LOGGER.warn("Cluster #{}({}) in cluster_helpers does not exist." - + " Please create the cluster or remove this entry", id, cluster); - } - } - resultSet.close(); - } - boolean invalidPlot = false; - for (Entry entry : noExist.entrySet()) { - String a = entry.getKey(); - invalidPlot = true; - LOGGER.warn("Warning! Found {} clusters in DB for non existent area; '{}'", noExist.get(a), a); - } - if (invalidPlot) { - LOGGER.warn("Warning! Please create the world(s) or remove the clusters using the purge command"); - } - } catch (SQLException e) { - LOGGER.error("Failed to load clusters", e); - } - return newClusters; - } - - @Override - public void setClusterName(final PlotCluster cluster, final String name) { - addClusterTask(cluster, new UniqueStatement("setClusterName") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setString(1, name); - statement.setInt(2, getClusterId(cluster)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "cluster_settings` SET `alias` = ? WHERE `cluster_id` = ?"); - } - }); - cluster.settings.setAlias(name); - } - - @Override - public void removeHelper(final PlotCluster cluster, final UUID uuid) { - addClusterTask(cluster, new UniqueStatement("removeHelper") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getClusterId(cluster)); - statement.setString(2, uuid.toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "cluster_helpers` WHERE `cluster_id` = ? AND `user_uuid` = ?"); - } - }); - } - - @Override - public void setHelper(final PlotCluster cluster, final UUID uuid) { - addClusterTask(cluster, new UniqueStatement("setHelper") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getClusterId(cluster)); - statement.setString(2, uuid.toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "cluster_helpers` (`cluster_id`, `user_uuid`) VALUES(?,?)"); - } - }); - } - - @Override - public void createCluster(final PlotCluster cluster) { - addClusterTask(cluster, new UniqueStatement("createCluster_" + cluster.hashCode()) { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, cluster.getP1().getX()); - statement.setInt(2, cluster.getP1().getY()); - statement.setInt(3, cluster.getP2().getX()); - statement.setInt(4, cluster.getP2().getY()); - statement.setString(5, cluster.owner.toString()); - statement.setString(6, cluster.area.toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - SQLManager.this.CREATE_CLUSTER, - Statement.RETURN_GENERATED_KEYS - ); - } - - @Override - public void execute(PreparedStatement statement) { - } - - @Override - public void addBatch(PreparedStatement statement) throws SQLException { - statement.execute(); - try (ResultSet keys = supportsGetGeneratedKeys ? statement.getGeneratedKeys() : statement.getResultSet()) { - if (keys.next()) { - cluster.temp = keys.getInt(1); - } - } - } - }); - addClusterTask( - cluster, - new UniqueStatement("createCluster_settings_" + cluster.hashCode()) { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getClusterId(cluster)); - statement.setString(2, cluster.settings.getAlias()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "cluster_settings`(`cluster_id`, `alias`) VALUES(?, ?)"); - } - } - ); - } - - @Override - public void resizeCluster(final PlotCluster current, PlotId min, PlotId max) { - final PlotId pos1 = PlotId.of(current.getP1().getX(), current.getP1().getY()); - final PlotId pos2 = PlotId.of(current.getP2().getX(), current.getP2().getY()); - current.setP1(min); - current.setP2(max); - - addClusterTask(current, new UniqueStatement("resizeCluster") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, pos1.getX()); - statement.setInt(2, pos1.getY()); - statement.setInt(3, pos2.getX()); - statement.setInt(4, pos2.getY()); - statement.setInt(5, getClusterId(current)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "cluster` SET `pos1_x` = ?, `pos1_z` = ?, `pos2_x` = ?, `pos2_z` = ? WHERE `id` = ?"); - } - }); - } - - @Override - public void setPosition(final PlotCluster cluster, final String position) { - addClusterTask(cluster, new UniqueStatement("setPosition") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setString(1, position); - statement.setInt(2, getClusterId(cluster)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "cluster_settings` SET `position` = ? WHERE `cluster_id` = ?"); - } - }); - } - - @Override - public void removeInvited(final PlotCluster cluster, final UUID uuid) { - addClusterTask(cluster, new UniqueStatement("removeInvited") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getClusterId(cluster)); - statement.setString(2, uuid.toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "cluster_invited` WHERE `cluster_id` = ? AND `user_uuid` = ?"); - } - }); - } - - @Override - public void setInvited(final PlotCluster cluster, final UUID uuid) { - addClusterTask(cluster, new UniqueStatement("setInvited") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getClusterId(cluster)); - statement.setString(2, uuid.toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "cluster_invited` (`cluster_id`, `user_uuid`) VALUES(?,?)"); - } - }); - } - - @Override - public boolean deleteTables() { - try (Statement stmt = this.connection.createStatement(); - PreparedStatement statement = this.connection - .prepareStatement("DROP TABLE `" + this.prefix + "plot`")) { - close(); - this.closed = false; - SQLManager.this.connection = this.database.forceConnection(); - stmt.addBatch("DROP TABLE `" + this.prefix + "cluster_invited`"); - stmt.addBatch("DROP TABLE `" + this.prefix + "cluster_helpers`"); - stmt.addBatch("DROP TABLE `" + this.prefix + "cluster`"); - stmt.addBatch("DROP TABLE `" + this.prefix + "plot_rating`"); - stmt.addBatch("DROP TABLE `" + this.prefix + "plot_settings`"); - stmt.addBatch("DROP TABLE `" + this.prefix + "plot_comments`"); - stmt.addBatch("DROP TABLE `" + this.prefix + "plot_trusted`"); - stmt.addBatch("DROP TABLE `" + this.prefix + "plot_helpers`"); - stmt.addBatch("DROP TABLE `" + this.prefix + "plot_denied`"); - stmt.executeBatch(); - stmt.clearBatch(); - statement.executeUpdate(); - } catch (ClassNotFoundException | SQLException e) { - e.printStackTrace(); - - } - return true; - } - - @SuppressWarnings({"unchecked", "unused"}) - @Override - public void validateAllPlots(Set toValidate) { - if (!isValid()) { - reconnect(); - } - LOGGER.info( - "All DB transactions during this session are being validated (This may take a while if corrections need to be made)"); - commit(); - while (true) { - if (!sendBatch()) { - break; - } - } - try { - if (this.connection.getAutoCommit()) { - this.connection.setAutoCommit(false); - } - } catch (SQLException e) { - e.printStackTrace(); - } - HashMap> database = getPlots(); - ArrayList toCreate = new ArrayList<>(); - for (Plot plot : toValidate) { - if (plot.temp == -1) { - continue; - } - if (plot.getArea() == null) { - LOGGER.error("CRITICAL ERROR IN VALIDATION TASK: {}", plot); - LOGGER.error("PLOT AREA CANNOT BE NULL! SKIPPING PLOT!"); - LOGGER.info("Delete this entry from your database or set `database-purger: true` in the settings.yml"); - continue; - } - if (database == null) { - LOGGER.error("CRITICAL ERROR IN VALIDATION TASK!"); - LOGGER.error("DATABASE VARIABLE CANNOT BE NULL! NOW ENDING VALIDATION!"); - break; - } - HashMap worldPlots = database.get(plot.getArea().toString()); - if (worldPlots == null) { - toCreate.add(plot); - continue; - } - Plot dataPlot = worldPlots.remove(plot.getId()); - if (dataPlot == null) { - toCreate.add(plot); - continue; - } - // owner - if (!plot.getOwnerAbs().equals(dataPlot.getOwnerAbs())) { - setOwner(plot, plot.getOwnerAbs()); - } - // trusted - if (!plot.getTrusted().equals(dataPlot.getTrusted())) { - HashSet toAdd = (HashSet) plot.getTrusted().clone(); - HashSet toRemove = (HashSet) dataPlot.getTrusted().clone(); - toRemove.removeAll(plot.getTrusted()); - toAdd.removeAll(dataPlot.getTrusted()); - if (!toRemove.isEmpty()) { - for (UUID uuid : toRemove) { - removeTrusted(plot, uuid); - } - } - if (!toAdd.isEmpty()) { - for (UUID uuid : toAdd) { - setTrusted(plot, uuid); - } - } - } - if (!plot.getMembers().equals(dataPlot.getMembers())) { - HashSet toAdd = (HashSet) plot.getMembers().clone(); - HashSet toRemove = (HashSet) dataPlot.getMembers().clone(); - toRemove.removeAll(plot.getMembers()); - toAdd.removeAll(dataPlot.getMembers()); - if (!toRemove.isEmpty()) { - for (UUID uuid : toRemove) { - removeMember(plot, uuid); - } - } - if (!toAdd.isEmpty()) { - for (UUID uuid : toAdd) { - setMember(plot, uuid); - } - } - } - if (!plot.getDenied().equals(dataPlot.getDenied())) { - HashSet toAdd = (HashSet) plot.getDenied().clone(); - HashSet toRemove = (HashSet) dataPlot.getDenied().clone(); - toRemove.removeAll(plot.getDenied()); - toAdd.removeAll(dataPlot.getDenied()); - if (!toRemove.isEmpty()) { - for (UUID uuid : toRemove) { - removeDenied(plot, uuid); - } - } - if (!toAdd.isEmpty()) { - for (UUID uuid : toAdd) { - setDenied(plot, uuid); - } - } - } - boolean[] pm = plot.getMerged(); - boolean[] dm = dataPlot.getMerged(); - if (pm[0] != dm[0] || pm[1] != dm[1]) { - setMerged(dataPlot, plot.getMerged()); - } - Set> pf = plot.getFlags(); - Set> df = dataPlot.getFlags(); - if (!pf.isEmpty() && !df.isEmpty()) { - if (pf.size() != df.size() || !StringMan - .isEqual(StringMan.joinOrdered(pf, ","), StringMan.joinOrdered(df, ","))) { - // setFlags(plot, pf); - // TODO: Re-implement - } - } - } - - for (Entry> entry : database.entrySet()) { - HashMap map = entry.getValue(); - if (!map.isEmpty()) { - for (Entry entry2 : map.entrySet()) { - // TODO implement this when sure safe" - } - } - } - commit(); - } - - @Override - public void replaceWorld( - final String oldWorld, final String newWorld, final PlotId min, - final PlotId max - ) { - addGlobalTask(() -> { - if (min == null) { - try (PreparedStatement stmt = SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "plot` SET `world` = ? WHERE `world` = ?")) { - stmt.setString(1, newWorld); - stmt.setString(2, oldWorld); - stmt.executeUpdate(); - } catch (SQLException e) { - e.printStackTrace(); - } - try (PreparedStatement stmt = SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "cluster` SET `world` = ? WHERE `world` = ?")) { - stmt.setString(1, newWorld); - stmt.setString(2, oldWorld); - stmt.executeUpdate(); - } catch (SQLException e) { - e.printStackTrace(); - } - } else { - try (PreparedStatement stmt = SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "plot` SET `world` = ? WHERE `world` = ? AND `plot_id_x` BETWEEN ? AND ? AND `plot_id_z` BETWEEN ? AND ?")) { - stmt.setString(1, newWorld); - stmt.setString(2, oldWorld); - stmt.setInt(3, min.getX()); - stmt.setInt(4, max.getX()); - stmt.setInt(5, min.getY()); - stmt.setInt(6, max.getY()); - stmt.executeUpdate(); - } catch (SQLException e) { - e.printStackTrace(); - } - try (PreparedStatement stmt = SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "cluster` SET `world` = ? WHERE `world` = ? AND `pos1_x` <= ? AND `pos1_z` <= ? AND `pos2_x` >= ? AND `pos2_z` >= ?")) { - stmt.setString(1, newWorld); - stmt.setString(2, oldWorld); - stmt.setInt(3, max.getX()); - stmt.setInt(4, max.getY()); - stmt.setInt(5, min.getX()); - stmt.setInt(6, min.getY()); - stmt.executeUpdate(); - } catch (SQLException e) { - e.printStackTrace(); - } - } - }); - } - - @Override - public void replaceUUID(final UUID old, final UUID now) { - addGlobalTask(() -> { - try (Statement stmt = SQLManager.this.connection.createStatement()) { - stmt.executeUpdate( - "UPDATE `" + SQLManager.this.prefix + "cluster` SET `owner` = '" + now - .toString() + "' WHERE `owner` = '" + old.toString() + '\''); - stmt.executeUpdate( - "UPDATE `" + SQLManager.this.prefix + "cluster_helpers` SET `user_uuid` = '" - + now + "' WHERE `user_uuid` = '" + old + '\''); - stmt.executeUpdate( - "UPDATE `" + SQLManager.this.prefix + "cluster_invited` SET `user_uuid` = '" - + now + "' WHERE `user_uuid` = '" + old + '\''); - stmt.executeUpdate( - "UPDATE `" + SQLManager.this.prefix + "plot` SET `owner` = '" + now - + "' WHERE `owner` = '" + old + '\''); - stmt.executeUpdate( - "UPDATE `" + SQLManager.this.prefix + "plot_denied` SET `user_uuid` = '" + now + "' WHERE `user_uuid` = '" + old + '\''); - stmt.executeUpdate( - "UPDATE `" + SQLManager.this.prefix + "plot_helpers` SET `user_uuid` = '" + now + "' WHERE `user_uuid` = '" + old + '\''); - stmt.executeUpdate( - "UPDATE `" + SQLManager.this.prefix + "plot_trusted` SET `user_uuid` = '" + now + "' WHERE `user_uuid` = '" + old + '\''); - } catch (SQLException e) { - e.printStackTrace(); - } - }); - } - - @Override - public void close() { - try { - this.closed = true; - this.connection.close(); - } catch (SQLException e) { - e.printStackTrace(); - } - } - - private record LegacySettings( - int id, - PlotSettings settings - ) { - - } - - public abstract static class UniqueStatement { - - public final String method; - - public UniqueStatement(String method) { - this.method = method; - } - - public void addBatch(PreparedStatement statement) throws SQLException { - statement.addBatch(); - } - - public void execute(PreparedStatement statement) throws SQLException { - statement.executeBatch(); - } - - public abstract PreparedStatement get() throws SQLException; - - public abstract void set(PreparedStatement statement) throws SQLException; - - } - - private record UUIDPair(int id, UUID uuid) { - - } - -} diff --git a/Core/src/main/java/com/plotsquared/core/database/SQLite.java b/Core/src/main/java/com/plotsquared/core/database/SQLite.java deleted file mode 100644 index c34be4c59d..0000000000 --- a/Core/src/main/java/com/plotsquared/core/database/SQLite.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.core.database; - -import com.plotsquared.core.PlotSquared; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.io.File; -import java.io.IOException; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -/** - * Connects to and uses a SQLite database. - */ -public class SQLite extends Database { - - private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + SQLite.class.getSimpleName()); - - private final String dbLocation; - private Connection connection; - - /** - * Creates a new SQLite instance - * - * @param dbLocation Location of the Database (Must end in .db) - */ - public SQLite(File dbLocation) { - this.dbLocation = dbLocation.getAbsolutePath(); - } - - @Override - public Connection openConnection() throws SQLException, ClassNotFoundException { - if (checkConnection()) { - return this.connection; - } - if (!PlotSquared.platform().getDirectory().exists()) { - PlotSquared.platform().getDirectory().mkdirs(); - } - File file = new File(this.dbLocation); - if (!file.exists()) { - try { - file.createNewFile(); - } catch (IOException ignored) { - LOGGER.error("Unable to create database"); - } - } - Class.forName("org.sqlite.JDBC"); - this.connection = DriverManager.getConnection("jdbc:sqlite:" + this.dbLocation); - return this.connection; - } - - @Override - public boolean checkConnection() throws SQLException { - return (this.connection != null) && !this.connection.isClosed(); - } - - @Override - public Connection getConnection() { - return this.connection; - } - - @Override - public boolean closeConnection() throws SQLException { - if (this.connection == null) { - return false; - } - this.connection.close(); - this.connection = null; - return true; - } - - @Override - public ResultSet querySQL(String query) throws SQLException, ClassNotFoundException { - if (checkConnection()) { - openConnection(); - } - try (Statement statement = this.connection.createStatement()) { - return statement.executeQuery(query); - } - } - - @Override - public int updateSQL(String query) throws SQLException, ClassNotFoundException { - if (checkConnection()) { - openConnection(); - } - try (Statement statement = this.connection.createStatement()) { - return statement.executeUpdate(query); - } - } - - @Override - public Connection forceConnection() throws SQLException, ClassNotFoundException { - Class.forName("org.sqlite.JDBC"); - this.connection = DriverManager.getConnection("jdbc:sqlite:" + this.dbLocation); - return this.connection; - } - -} diff --git a/Core/src/main/java/com/plotsquared/core/database/StmtMod.java b/Core/src/main/java/com/plotsquared/core/database/StmtMod.java deleted file mode 100644 index 2b31e4b3df..0000000000 --- a/Core/src/main/java/com/plotsquared/core/database/StmtMod.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.core.database; - -import com.plotsquared.core.util.StringMan; - -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -public abstract class StmtMod { - - public abstract String getCreateMySQL(int size); - - public String getCreateMySQL(int size, String query, int params) { - StringBuilder statement = new StringBuilder(query); - for (int i = 0; i < size - 1; i++) { - statement.append('(').append(StringMan.repeat(",?", params).substring(1)).append("),"); - } - statement.append('(').append(StringMan.repeat(",?", params).substring(1)).append(')'); - return statement.toString(); - } - - public String getCreateSQLite(int size, String query, int params) { - String modParams = StringMan.repeat(",?", params).substring(1); - return IntStream.range(0, size - 1).mapToObj(i -> "UNION SELECT " + modParams + ' ') - .collect(Collectors.joining("", query, "")); - } - - public abstract String getCreateSQLite(int size); - - public abstract String getCreateSQL(); - - public abstract void setMySQL(PreparedStatement stmt, int i, T obj) throws SQLException; - - public abstract void setSQLite(PreparedStatement stmt, int i, T obj) throws SQLException; - - public abstract void setSQL(PreparedStatement stmt, T obj) throws SQLException; - -} diff --git a/Core/src/test/java/com/plotsquared/core/database/AbstractDBTest.java b/Core/src/test/java/com/plotsquared/core/database/AbstractDBTest.java deleted file mode 100644 index 18e0a5f413..0000000000 --- a/Core/src/test/java/com/plotsquared/core/database/AbstractDBTest.java +++ /dev/null @@ -1,278 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.core.database; - -import com.plotsquared.core.plot.Plot; -import com.plotsquared.core.plot.PlotArea; -import com.plotsquared.core.plot.PlotCluster; -import com.plotsquared.core.plot.PlotId; -import com.plotsquared.core.plot.comment.PlotComment; -import com.plotsquared.core.plot.flag.PlotFlag; -import com.plotsquared.core.util.task.RunnableVal; -import org.checkerframework.checker.nullness.qual.NonNull; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; - -public class AbstractDBTest implements AbstractDB { - - @Override - public void setOwner(Plot plot, UUID uuid) { - } - - @Override - public void createPlotsAndData(List plots, Runnable whenDone) { - } - - @Override - public void createPlotSafe(Plot plot, Runnable success, Runnable failure) { - } - - @Override - public void createTables() { - } - - @Override - public void delete(Plot plot) { - } - - @Override - public void deleteSettings(Plot plot) { - } - - @Override - public void deleteHelpers(Plot plot) { - } - - @Override - public void deleteTrusted(Plot plot) { - } - - @Override - public void deleteDenied(Plot plot) { - } - - @Override - public void deleteComments(Plot plot) { - } - - @Override - public void deleteRatings(Plot plot) { - } - - @Override - public void delete(PlotCluster cluster) { - } - - @Override - public void addPersistentMeta(UUID uuid, String key, byte[] meta, boolean delete) { - } - - @Override - public void removePersistentMeta(UUID uuid, String key) { - } - - @Override - public void getPersistentMeta(UUID uuid, RunnableVal> result) { - } - - @Override - public void createPlotSettings(int id, Plot plot) { - } - - @Override - public int getId(Plot plot) { - return 0; - } - - @Override - public int getClusterId(PlotCluster cluster) { - return 0; - } - - @Override - public boolean convertFlags() { - return true; - } - - @Override - public HashMap> getPlots() { - return null; - } - - @Override - public void validateAllPlots(Set toValidate) { - } - - @Override - public HashMap> getClusters() { - return null; - } - - @Override - public void setMerged(Plot plot, boolean[] merged) { - } - - @Override - public CompletableFuture swapPlots(Plot plot1, Plot plot2) { - return CompletableFuture.completedFuture(true); - } - - @Override - public void setFlag(Plot plot, PlotFlag flag) { - } - - @Override - public void removeFlag(Plot plot, PlotFlag flag) { - } - - @Override - public void setClusterName(PlotCluster cluster, String name) { - } - - @Override - public void setAlias(Plot plot, String alias) { - } - - @Override - public void purgeIds(Set uniqueIds) { - } - - @Override - public void purge(PlotArea area, Set plotIds) { - } - - @Override - public void setPosition(Plot plot, String position) { - } - - @Override - public void setPosition(PlotCluster cluster, String position) { - } - - @Override - public void removeTrusted(Plot plot, UUID uuid) { - } - - @Override - public void removeHelper(PlotCluster cluster, UUID uuid) { - } - - @Override - public void removeMember(Plot plot, UUID uuid) { - } - - @Override - public void removeInvited(PlotCluster cluster, UUID uuid) { - } - - @Override - public void setTrusted(Plot plot, UUID uuid) { - } - - @Override - public void setHelper(PlotCluster cluster, UUID uuid) { - } - - @Override - public void setMember(Plot plot, UUID uuid) { - } - - @Override - public void setInvited(PlotCluster cluster, UUID uuid) { - } - - @Override - public void removeDenied(Plot plot, UUID uuid) { - } - - @Override - public void setDenied(Plot plot, UUID uuid) { - } - - @Override - public HashMap getRatings(Plot plot) { - return null; - } - - @Override - public void setRating(Plot plot, UUID rater, int value) { - } - - @Override - public void removeComment(Plot plot, PlotComment comment) { - } - - @Override - public void clearInbox(Plot plot, String inbox) { - } - - @Override - public void setComment(Plot plot, PlotComment comment) { - } - - @Override - public void getComments( - @NonNull Plot plot, String inbox, - RunnableVal> whenDone - ) { - } - - @Override - public void createPlotAndSettings(Plot plot, Runnable whenDone) { - } - - @Override - public void createCluster(PlotCluster cluster) { - } - - @Override - public void resizeCluster(PlotCluster current, PlotId min, PlotId max) { - } - - @Override - public void movePlot(Plot originalPlot, Plot newPlot) { - } - - @Override - public void replaceUUID(UUID old, UUID now) { - } - - @Override - public boolean deleteTables() { - return false; - } - - @Override - public void close() { - } - - @Override - public void replaceWorld(String oldWorld, String newWorld, PlotId min, PlotId max) { - } - - @Override - public void updateTables(int[] oldVersion) { - } - -} diff --git a/Core/src/test/java/com/plotsquared/core/plot/FlagTest.java b/Core/src/test/java/com/plotsquared/core/plot/FlagTest.java deleted file mode 100644 index c3063b37d5..0000000000 --- a/Core/src/test/java/com/plotsquared/core/plot/FlagTest.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.core.plot; - -import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.AbstractDBTest; -import com.plotsquared.core.database.DBFunc; -import com.plotsquared.core.plot.flag.FlagParseException; -import com.plotsquared.core.plot.flag.PlotFlag; -import com.plotsquared.core.plot.flag.implementations.PlotTitleFlag; -import com.plotsquared.core.plot.flag.implementations.UseFlag; -import com.sk89q.worldedit.world.item.ItemType; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class FlagTest { - - private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + FlagTest.class.getSimpleName()); - - private ItemType testBlock; - - @BeforeEach - public void setUp() throws Exception { - //EventUtil.manager = new EventUtilTest(); - DBFunc.dbManager = new AbstractDBTest(); - } - -// @Test public void flagTest() throws Exception { -// Plot plot = new Plot(null, PlotId.of(0, 0)); -// plot.owner = UUID.fromString("84499644-ad72-454b-a19d-f28c28df382b"); -// //plot.setFlag(use, use.parseValue("33,33:1,6:4")); //TODO fix this so FlagTest will run during compile -// Optional flag = plot.getFlag(use); -// if (flag.isPresent()) { -// LOGGER.info(Flags.USE.valueToString(flag.get())); -// testBlock = ItemTypes.BONE_BLOCK; -// flag.get().add(testBlock); -// } -// flag.ifPresent(collection -> LOGGER.info(Flags.USE.valueToString(collection))); -// Optional> flag2 = plot.getFlag(Flags.USE); -// if (flag2.isPresent()) { -// // assertThat(flag2.get(), (Matcher>) IsCollectionContaining.hasItem(testBlock)); -// } -// if (flag.isPresent() && flag2.isPresent()) { -// assertEquals(flag.get(), flag2.get()); -// } -// } - - @Test - public void testFlagName() { - String flagName = PlotFlag.getFlagName(UseFlag.class); - Assertions.assertEquals("use", flagName); - } - - @Test - public void shouldSuccessfullyParseTitleFlagWithTitleSingularAndSubTitleEmpty() { - Assertions.assertDoesNotThrow(() -> { - var title = PlotTitleFlag.TITLE_FLAG_DEFAULT.parse("\"test\" \"\"").getValue(); - Assertions.assertEquals("test", title.title()); - Assertions.assertEquals("", title.subtitle()); - }, "Should not throw a FlagParseException"); - } - - @Test - public void shouldSuccessfullyParseTitleFlagWithTitleMultipleWordsAndSubTitleEmpty() { - Assertions.assertDoesNotThrow(() -> { - var title = PlotTitleFlag.TITLE_FLAG_DEFAULT.parse("\"test hello test\" \"\"").getValue(); - Assertions.assertEquals("test hello test", title.title()); - Assertions.assertEquals("", title.subtitle()); - }, "Should not throw a FlagParseException"); - } - - @Test - public void shouldSuccessfullyParseTitleFlagWithTitleMultipleWordsAndSubTitleMultipleWords() { - Assertions.assertDoesNotThrow(() -> { - var title = PlotTitleFlag.TITLE_FLAG_DEFAULT.parse("\"test hello test\" \"a very long subtitle\"").getValue(); - Assertions.assertEquals("test hello test", title.title()); - Assertions.assertEquals("a very long subtitle", title.subtitle()); - }, "Should not throw a FlagParseException"); - } - - @Test - public void shouldSuccessfullyParseTitleFlagWithTitleEmptyAndSubTitleSingleWord() { - Assertions.assertDoesNotThrow(() -> { - var title = PlotTitleFlag.TITLE_FLAG_DEFAULT.parse("\"\" \"single\"").getValue(); - Assertions.assertEquals("", title.title()); - Assertions.assertEquals("single", title.subtitle()); - }, "Should not throw a FlagParseException"); - } - - @Test - public void shouldExtractTitleWhenASingleDoubleQuoteAtEndOfTitle() { - Assertions.assertDoesNotThrow(() -> { - var plotTitle = PlotTitleFlag.TITLE_FLAG_DEFAULT.parse("title\"").getValue(); - Assertions.assertEquals("title", plotTitle.title()); - Assertions.assertEquals("", plotTitle.subtitle()); - }, "Should not throw a FlagParseException"); - } - - @Test - public void shouldThrowFlagParseExceptionWithQuotesGreater4() { - var exception = Assertions.assertThrows( - FlagParseException.class, - () -> PlotTitleFlag.TITLE_FLAG_DEFAULT.parse("\"title\" \"subtitle\" \"more\""), - "Needs to throw a FlagParseException" - ); - Assertions.assertTrue(exception.getErrorMessage() instanceof TranslatableCaption); - Assertions.assertEquals( - "flags.flag_error_title", - ((TranslatableCaption) exception.getErrorMessage()).getKey() - ); - } - -} From 2bf312ffd426bad840cd2345f9be9cda41f87cc4 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Thu, 4 Sep 2025 22:40:24 +0200 Subject: [PATCH 051/141] feat: add JAXB runtime and Hibernate community dialects dependencies for enhanced database support --- Core/build.gradle.kts | 3 +++ gradle/libs.versions.toml | 3 +++ 2 files changed, 6 insertions(+) diff --git a/Core/build.gradle.kts b/Core/build.gradle.kts index 6225359585..22b87286bb 100644 --- a/Core/build.gradle.kts +++ b/Core/build.gradle.kts @@ -47,6 +47,9 @@ dependencies { // Database api(libs.hibernateCore) + runtimeOnly(libs.jaxbRuntime) + annotationProcessor(libs.hibernateCore) + api(libs.hibernateCommunityDialects) api(libs.jpaApi) api(libs.flywayCore) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e6e96b17ad..db110c725b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -36,6 +36,7 @@ serverlib = "2.3.7" jpa-api = "3.2.0" hibernate-core = "7.1.0.Final" flyway-core = "11.11.2" +jaxbRuntime = "4.0.5" # JDBC Drivers mariadb-java-client = "3.5.5" sqlite-jdbc = "3.50.3.0" @@ -88,7 +89,9 @@ serverlib = { group = "dev.notmyfault.serverlib", name = "ServerLib", version.re # Database jpaApi = { group = "jakarta.persistence", name = "jakarta.persistence-api", version.ref = "jpa-api" } hibernateCore = { group = "org.hibernate.orm", name = "hibernate-core", version.ref = "hibernate-core" } +hibernateCommunityDialects = { group = "org.hibernate.orm", name = "hibernate-community-dialects", version.ref = "hibernate-core" } flywayCore = { group = "org.flywaydb", name = "flyway-core", version.ref = "flyway-core" } +jaxbRuntime = { group = "org.glassfish.jaxb", name = "jaxb-runtime", version.ref = "jaxbRuntime" } # JDBC Drivers mariadbJavaClient = { group = "org.mariadb.jdbc", name = "mariadb-java-client", version.ref = "mariadb-java-client" } sqliteJdbc = { group = "org.xerial", name = "sqlite-jdbc", version.ref = "sqlite-jdbc" } From 57f637a87d2339bec9a1f9b94d929b27912877b0 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Thu, 4 Sep 2025 22:41:03 +0200 Subject: [PATCH 052/141] feat: update Hibernate configuration to create schema on startup --- .../core/persistence/config/JpaPropertiesProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java b/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java index 549041e0e0..589e9a3de5 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java @@ -34,7 +34,7 @@ public Map getProperties() { } // Schema is managed by Flyway; only validate with Hibernate - props.put("hibernate.hbm2ddl.auto", "validate"); + props.put("hibernate.hbm2ddl.auto", "create"); props.put("hibernate.show_sql", false); props.put("hibernate.format_sql", false); From c8e14d37ac6d93b222b081e8ad88ef77a704be18 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Thu, 4 Sep 2025 22:41:28 +0200 Subject: [PATCH 053/141] feat: enhance persistence module with eager binding and context class loader management --- .../persistence/config/PersistenceModule.java | 27 ++++++++++++++----- .../main/resources/META-INF/persistence.xml | 20 +++++++++++++- 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java b/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java index b651b81848..c4641c2d1a 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java @@ -36,6 +36,7 @@ import org.flywaydb.core.Flyway; import java.util.Map; +import java.util.function.Supplier; public class PersistenceModule extends AbstractModule { @@ -55,21 +56,35 @@ protected void configure() { bind(ClusterHelperRepository.class).to(ClusterHelperRepositoryJpa.class); bind(ClusterInvitedRepository.class).to(ClusterInvitedRepositoryJpa.class); bind(ClusterSettingsRepository.class).to(ClusterSettingsRepositoryJpa.class); + bind(JpaPropertiesProvider.class).asEagerSingleton(); // Eagerly run Flyway migrations on startup bind(FlywayBootstrap.class).asEagerSingleton(); } - @Provides - EntityManager provideEm(EntityManagerFactory emf) { - return emf.createEntityManager(); - } - @Provides @Singleton EntityManagerFactory provideEmf(JpaPropertiesProvider jpaPropertiesProvider) { Map props = jpaPropertiesProvider.getProperties(); - return Persistence.createEntityManagerFactory("plotsquaredPU", props); + return syncThreadForServiceLoader(() -> Persistence.createEntityManagerFactory("plotsquaredPU", props)); + } + + + private T syncThreadForServiceLoader(Supplier supplier) { + Thread currentThread = Thread.currentThread(); + ClassLoader originalClassLoader = currentThread.getContextClassLoader(); + ClassLoader pluginClassLoader = this.getClass().getClassLoader(); + try { + currentThread.setContextClassLoader(pluginClassLoader); + return supplier.get(); + } finally { + currentThread.setContextClassLoader(originalClassLoader); + } + } + + @Provides + EntityManager provideEm(EntityManagerFactory emf) { + return emf.createEntityManager(); } @Provides diff --git a/Core/src/main/resources/META-INF/persistence.xml b/Core/src/main/resources/META-INF/persistence.xml index ebf0be39cf..02b881244e 100644 --- a/Core/src/main/resources/META-INF/persistence.xml +++ b/Core/src/main/resources/META-INF/persistence.xml @@ -5,9 +5,27 @@ version="3.0"> org.hibernate.jpa.HibernatePersistenceProvider - false + com.plotsquared.core.persistence.entity.PlotEntity + com.plotsquared.core.persistence.entity.ClusterEntity + com.plotsquared.core.persistence.entity.ClusterHelperEntity + com.plotsquared.core.persistence.entity.ClusterInvitedEntity + com.plotsquared.core.persistence.entity.ClusterSettingsEntity + com.plotsquared.core.persistence.entity.ClusterUserId + com.plotsquared.core.persistence.entity.PlayerMetaEntity + com.plotsquared.core.persistence.entity.PlotCommentEntity + com.plotsquared.core.persistence.entity.PlotCommentId + com.plotsquared.core.persistence.entity.PlotDeniedEntity + com.plotsquared.core.persistence.entity.PlotEntity + com.plotsquared.core.persistence.entity.PlotFlagEntity + com.plotsquared.core.persistence.entity.PlotMembershipEntity + com.plotsquared.core.persistence.entity.PlotRatingEntity + com.plotsquared.core.persistence.entity.PlotRatingId + com.plotsquared.core.persistence.entity.PlotSettingsEntity + com.plotsquared.core.persistence.entity.PlotTrustedEntity + com.plotsquared.core.persistence.entity.PlotUserId + From 8c4015e5794c51eeed5f256e3f1e59a558d6c0b2 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Thu, 4 Sep 2025 22:47:57 +0200 Subject: [PATCH 054/141] feat: remove hbm2ddl.auto property from persistence.xml for improved schema management --- Core/src/main/resources/META-INF/persistence.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/src/main/resources/META-INF/persistence.xml b/Core/src/main/resources/META-INF/persistence.xml index 02b881244e..47ef663f04 100644 --- a/Core/src/main/resources/META-INF/persistence.xml +++ b/Core/src/main/resources/META-INF/persistence.xml @@ -25,7 +25,6 @@ com.plotsquared.core.persistence.entity.PlotUserId - From 3155dedb62f1e73fe1b2d95e016bfb03e98e73ef Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Thu, 4 Sep 2025 23:30:31 +0200 Subject: [PATCH 055/141] feat: add Flyway MySQL dependency for improved database migration support --- Core/build.gradle.kts | 1 + gradle/libs.versions.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/Core/build.gradle.kts b/Core/build.gradle.kts index 22b87286bb..5f17bb15a1 100644 --- a/Core/build.gradle.kts +++ b/Core/build.gradle.kts @@ -52,6 +52,7 @@ dependencies { api(libs.hibernateCommunityDialects) api(libs.jpaApi) api(libs.flywayCore) + runtimeOnly(libs.flywayMysql) runtimeOnly(libs.mariadbJavaClient) runtimeOnly(libs.sqliteJdbc) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index db110c725b..1cedfac10e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -91,6 +91,7 @@ jpaApi = { group = "jakarta.persistence", name = "jakarta.persistence-api", vers hibernateCore = { group = "org.hibernate.orm", name = "hibernate-core", version.ref = "hibernate-core" } hibernateCommunityDialects = { group = "org.hibernate.orm", name = "hibernate-community-dialects", version.ref = "hibernate-core" } flywayCore = { group = "org.flywaydb", name = "flyway-core", version.ref = "flyway-core" } +flywayMysql = { group = "org.flywaydb", name = "flyway-mysql", version.ref = "flyway-core" } jaxbRuntime = { group = "org.glassfish.jaxb", name = "jaxb-runtime", version.ref = "jaxbRuntime" } # JDBC Drivers mariadbJavaClient = { group = "org.mariadb.jdbc", name = "mariadb-java-client", version.ref = "mariadb-java-client" } From d852368c2216ad6b134e0768daea24a75d49e1eb Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Thu, 4 Sep 2025 23:37:00 +0200 Subject: [PATCH 056/141] feat: add GPL license headers to repository classes for compliance --- .../java/com/plotsquared/core/PlotSquared.java | 3 --- .../persistence/config/FlywayBootstrap.java | 18 ++++++++++++++++++ .../config/JpaPropertiesProvider.java | 18 ++++++++++++++++++ .../persistence/config/PersistenceModule.java | 18 ++++++++++++++++++ .../config/PrefixedNamingStrategy.java | 18 ++++++++++++++++++ .../core/persistence/entity/ClusterEntity.java | 18 ++++++++++++++++++ .../entity/ClusterHelperEntity.java | 18 ++++++++++++++++++ .../entity/ClusterInvitedEntity.java | 18 ++++++++++++++++++ .../entity/ClusterSettingsEntity.java | 18 ++++++++++++++++++ .../core/persistence/entity/ClusterUserId.java | 18 ++++++++++++++++++ .../persistence/entity/PlayerMetaEntity.java | 18 ++++++++++++++++++ .../persistence/entity/PlotCommentEntity.java | 18 ++++++++++++++++++ .../core/persistence/entity/PlotCommentId.java | 18 ++++++++++++++++++ .../persistence/entity/PlotDeniedEntity.java | 18 ++++++++++++++++++ .../core/persistence/entity/PlotEntity.java | 18 ++++++++++++++++++ .../persistence/entity/PlotFlagEntity.java | 18 ++++++++++++++++++ .../entity/PlotMembershipEntity.java | 18 ++++++++++++++++++ .../persistence/entity/PlotRatingEntity.java | 18 ++++++++++++++++++ .../core/persistence/entity/PlotRatingId.java | 18 ++++++++++++++++++ .../persistence/entity/PlotSettingsEntity.java | 18 ++++++++++++++++++ .../persistence/entity/PlotTrustedEntity.java | 18 ++++++++++++++++++ .../core/persistence/entity/PlotUserId.java | 18 ++++++++++++++++++ .../api/ClusterHelperRepository.java | 18 ++++++++++++++++++ .../api/ClusterInvitedRepository.java | 18 ++++++++++++++++++ .../repository/api/ClusterRepository.java | 18 ++++++++++++++++++ .../api/ClusterSettingsRepository.java | 18 ++++++++++++++++++ .../repository/api/PlayerMetaRepository.java | 18 ++++++++++++++++++ .../repository/api/PlotCommentRepository.java | 18 ++++++++++++++++++ .../repository/api/PlotDeniedRepository.java | 18 ++++++++++++++++++ .../repository/api/PlotFlagRepository.java | 18 ++++++++++++++++++ .../api/PlotMembershipRepository.java | 18 ++++++++++++++++++ .../repository/api/PlotRatingRepository.java | 18 ++++++++++++++++++ .../repository/api/PlotRepository.java | 18 ++++++++++++++++++ .../repository/api/PlotSettingsRepository.java | 18 ++++++++++++++++++ .../repository/api/PlotTrustedRepository.java | 18 ++++++++++++++++++ .../jpa/ClusterHelperRepositoryJpa.java | 18 ++++++++++++++++++ .../jpa/ClusterInvitedRepositoryJpa.java | 18 ++++++++++++++++++ .../repository/jpa/ClusterRepositoryJpa.java | 18 ++++++++++++++++++ .../jpa/ClusterSettingsRepositoryJpa.java | 18 ++++++++++++++++++ .../jpa/PlayerMetaRepositoryJpa.java | 18 ++++++++++++++++++ .../jpa/PlotCommentRepositoryJpa.java | 18 ++++++++++++++++++ .../jpa/PlotDeniedRepositoryJpa.java | 18 ++++++++++++++++++ .../repository/jpa/PlotFlagRepositoryJpa.java | 18 ++++++++++++++++++ .../jpa/PlotMembershipRepositoryJpa.java | 18 ++++++++++++++++++ .../jpa/PlotRatingRepositoryJpa.java | 18 ++++++++++++++++++ .../repository/jpa/PlotRepositoryJpa.java | 18 ++++++++++++++++++ .../jpa/PlotSettingsRepositoryJpa.java | 18 ++++++++++++++++++ .../jpa/PlotTrustedRepositoryJpa.java | 18 ++++++++++++++++++ 48 files changed, 846 insertions(+), 3 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/PlotSquared.java b/Core/src/main/java/com/plotsquared/core/PlotSquared.java index 50db209dcb..18152549b9 100644 --- a/Core/src/main/java/com/plotsquared/core/PlotSquared.java +++ b/Core/src/main/java/com/plotsquared/core/PlotSquared.java @@ -51,8 +51,6 @@ import com.plotsquared.core.plot.expiration.ExpiryTask; import com.plotsquared.core.plot.flag.GlobalFlagContainer; import com.plotsquared.core.plot.world.PlotAreaManager; -import com.plotsquared.core.plot.world.SinglePlotArea; -import com.plotsquared.core.plot.world.SinglePlotAreaManager; import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.FileUtils; import com.plotsquared.core.util.LegacyConverter; @@ -85,7 +83,6 @@ import java.net.URL; import java.nio.file.Files; import java.nio.file.StandardOpenOption; -import java.sql.SQLException; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/FlywayBootstrap.java b/Core/src/main/java/com/plotsquared/core/persistence/config/FlywayBootstrap.java index 1d8654af94..a3831e4813 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/FlywayBootstrap.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/FlywayBootstrap.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.config; import com.google.inject.Inject; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java b/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java index 589e9a3de5..75ad622b34 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.config; import com.google.inject.Singleton; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java b/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java index c4641c2d1a..68f6ff7ce4 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.config; import com.google.inject.AbstractModule; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/PrefixedNamingStrategy.java b/Core/src/main/java/com/plotsquared/core/persistence/config/PrefixedNamingStrategy.java index 21e21db40b..95fb6291e0 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/PrefixedNamingStrategy.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/PrefixedNamingStrategy.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.config; import org.hibernate.boot.model.naming.Identifier; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterEntity.java index 6a774a2d91..fd98081862 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterEntity.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.entity; import jakarta.persistence.Column; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterHelperEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterHelperEntity.java index 8daa100b3e..80b58decba 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterHelperEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterHelperEntity.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.entity; import jakarta.persistence.Column; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterInvitedEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterInvitedEntity.java index 81ff877a97..dfd6f902ca 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterInvitedEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterInvitedEntity.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.entity; import jakarta.persistence.Column; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterSettingsEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterSettingsEntity.java index c184f44d8f..b08c3f24bd 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterSettingsEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterSettingsEntity.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.entity; import jakarta.persistence.Column; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterUserId.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterUserId.java index fff1d45b05..7527cbaf4c 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterUserId.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterUserId.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.entity; import java.io.Serializable; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlayerMetaEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlayerMetaEntity.java index e6039d21d9..a0b4e36e68 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlayerMetaEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlayerMetaEntity.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.entity; import jakarta.persistence.Column; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotCommentEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotCommentEntity.java index ffb6447775..aeb3ab3a0d 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotCommentEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotCommentEntity.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.entity; import jakarta.persistence.Column; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotCommentId.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotCommentId.java index d38d863725..175baf32d2 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotCommentId.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotCommentId.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.entity; import java.io.Serializable; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotDeniedEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotDeniedEntity.java index 948755f3ef..9ff854e773 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotDeniedEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotDeniedEntity.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.entity; import jakarta.persistence.Column; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotEntity.java index 0169d7b1ae..ece8c2bfc4 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotEntity.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.entity; import jakarta.persistence.CascadeType; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotFlagEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotFlagEntity.java index d67f9c3234..b42ab3fdf7 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotFlagEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotFlagEntity.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.entity; import jakarta.persistence.Column; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotMembershipEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotMembershipEntity.java index dae514f873..c95c151def 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotMembershipEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotMembershipEntity.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.entity; import jakarta.persistence.Column; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotRatingEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotRatingEntity.java index 5bc665d630..65b2f8fe9f 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotRatingEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotRatingEntity.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.entity; import jakarta.persistence.Column; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotRatingId.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotRatingId.java index 190cf90888..528bd6acb8 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotRatingId.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotRatingId.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.entity; import java.io.Serializable; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotSettingsEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotSettingsEntity.java index e95561fdde..a6cc397eb5 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotSettingsEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotSettingsEntity.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.entity; import jakarta.persistence.Column; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotTrustedEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotTrustedEntity.java index 1c0b891ac6..b383d40edb 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotTrustedEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotTrustedEntity.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.entity; import jakarta.persistence.Column; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotUserId.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotUserId.java index c6cc88d01d..86d9b6632b 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotUserId.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotUserId.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.entity; import java.io.Serializable; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterHelperRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterHelperRepository.java index 18589de9e6..d33f2a5752 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterHelperRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterHelperRepository.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.repository.api; import java.util.List; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterInvitedRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterInvitedRepository.java index 89bbf8cbab..f6b3ca0494 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterInvitedRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterInvitedRepository.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.repository.api; import java.util.List; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterRepository.java index 3ec5d93160..8a467f3e05 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterRepository.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.repository.api; import com.plotsquared.core.persistence.entity.ClusterEntity; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterSettingsRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterSettingsRepository.java index c5389a84d4..fdb3392b76 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterSettingsRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterSettingsRepository.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.repository.api; import com.plotsquared.core.persistence.entity.ClusterSettingsEntity; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlayerMetaRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlayerMetaRepository.java index 25e85beecf..d5857b4361 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlayerMetaRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlayerMetaRepository.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.repository.api; import com.plotsquared.core.persistence.entity.PlayerMetaEntity; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotCommentRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotCommentRepository.java index 8151f2868f..47eb6d794b 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotCommentRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotCommentRepository.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.repository.api; import com.plotsquared.core.persistence.entity.PlotCommentEntity; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotDeniedRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotDeniedRepository.java index 45ba7903f1..d10d05baa1 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotDeniedRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotDeniedRepository.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.repository.api; import java.util.List; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotFlagRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotFlagRepository.java index 626a94ca13..2cc6baf297 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotFlagRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotFlagRepository.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.repository.api; import com.plotsquared.core.persistence.entity.PlotFlagEntity; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotMembershipRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotMembershipRepository.java index a45493ada1..d50347e747 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotMembershipRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotMembershipRepository.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.repository.api; import java.util.List; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRatingRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRatingRepository.java index 813563b2d4..a35f9ccb8f 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRatingRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRatingRepository.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.repository.api; import com.plotsquared.core.persistence.entity.PlotRatingEntity; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java index d5fff465f0..58c5e2eaf9 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.repository.api; import com.plotsquared.core.persistence.entity.PlotEntity; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotSettingsRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotSettingsRepository.java index 3eedba2036..494023e2f2 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotSettingsRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotSettingsRepository.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.repository.api; import com.plotsquared.core.persistence.entity.PlotSettingsEntity; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotTrustedRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotTrustedRepository.java index 224ce8850b..363cb42216 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotTrustedRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotTrustedRepository.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.repository.api; import java.util.List; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterHelperRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterHelperRepositoryJpa.java index 04a4c9f207..3e734c5cb3 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterHelperRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterHelperRepositoryJpa.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.repository.jpa; import com.google.inject.Inject; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterInvitedRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterInvitedRepositoryJpa.java index d4cca771ed..85bd1cfb69 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterInvitedRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterInvitedRepositoryJpa.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.repository.jpa; import com.google.inject.Inject; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterRepositoryJpa.java index 9a9fd79d03..3925a952c5 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterRepositoryJpa.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.repository.jpa; import com.google.inject.Inject; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterSettingsRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterSettingsRepositoryJpa.java index 1a8d4744c2..2f229bfde8 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterSettingsRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterSettingsRepositoryJpa.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.repository.jpa; import com.google.inject.Inject; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlayerMetaRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlayerMetaRepositoryJpa.java index 7afb123008..622bdff529 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlayerMetaRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlayerMetaRepositoryJpa.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.repository.jpa; import com.google.inject.Inject; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotCommentRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotCommentRepositoryJpa.java index 41afbc5d31..2a4e733235 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotCommentRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotCommentRepositoryJpa.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.repository.jpa; import com.google.inject.Inject; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotDeniedRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotDeniedRepositoryJpa.java index 9fd0033e60..8748f677b8 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotDeniedRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotDeniedRepositoryJpa.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.repository.jpa; import com.google.inject.Inject; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotFlagRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotFlagRepositoryJpa.java index 70717a191a..0605fe42fd 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotFlagRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotFlagRepositoryJpa.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.repository.jpa; import com.google.inject.Inject; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotMembershipRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotMembershipRepositoryJpa.java index 1383c69a90..c81dc861a5 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotMembershipRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotMembershipRepositoryJpa.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.repository.jpa; import com.google.inject.Inject; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRatingRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRatingRepositoryJpa.java index 796480e273..488d5f543b 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRatingRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRatingRepositoryJpa.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.repository.jpa; import com.google.inject.Inject; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java index c502594d93..8a2cd111c3 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.repository.jpa; import com.google.inject.Inject; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotSettingsRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotSettingsRepositoryJpa.java index a54ac8b30f..8b99e8b23a 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotSettingsRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotSettingsRepositoryJpa.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.repository.jpa; import com.google.inject.Inject; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotTrustedRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotTrustedRepositoryJpa.java index af86215881..7ed1ef51db 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotTrustedRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotTrustedRepositoryJpa.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.repository.jpa; import com.google.inject.Inject; From 2296957d163ebe4805a7a41de82cabbc4ed1e98f Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 09:29:21 +0200 Subject: [PATCH 057/141] feat: add versioning and author information to repository interfaces for clarity --- .../repository/api/ClusterHelperRepository.java | 5 +++++ .../repository/api/ClusterInvitedRepository.java | 5 +++++ .../repository/api/ClusterRepository.java | 8 +++++++- .../repository/api/ClusterSettingsRepository.java | 5 +++++ .../repository/api/PlayerMetaRepository.java | 5 +++++ .../repository/api/PlotCommentRepository.java | 5 +++++ .../repository/api/PlotDeniedRepository.java | 5 +++++ .../repository/api/PlotFlagRepository.java | 5 +++++ .../repository/api/PlotMembershipRepository.java | 5 +++++ .../repository/api/PlotRatingRepository.java | 5 +++++ .../persistence/repository/api/PlotRepository.java | 5 +++++ .../repository/api/PlotSettingsRepository.java | 5 +++++ .../repository/api/PlotTrustedRepository.java | 5 +++++ .../persistence/repository/api/package-info.java | 12 ++++++++++++ 14 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/repository/api/package-info.java diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterHelperRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterHelperRepository.java index d33f2a5752..27731ae78b 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterHelperRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterHelperRepository.java @@ -24,6 +24,11 @@ * Repository abstraction for managing helper users associated with a cluster. * Implementations are responsible for persisting and retrieving associations * between a cluster and player UUIDs who act as helpers. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites */ public interface ClusterHelperRepository { /** diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterInvitedRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterInvitedRepository.java index f6b3ca0494..f47c12ae2f 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterInvitedRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterInvitedRepository.java @@ -24,6 +24,11 @@ * Repository abstraction for managing invited users for a cluster. * Implementations persist associations between clusters and player UUIDs * that have been invited to the cluster but may not yet be members/helpers. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites */ public interface ClusterInvitedRepository { /** diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterRepository.java index 8a467f3e05..6c2aec5234 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterRepository.java @@ -19,12 +19,18 @@ package com.plotsquared.core.persistence.repository.api; import com.plotsquared.core.persistence.entity.ClusterEntity; +import com.plotsquared.core.plot.PlotId; import java.util.List; import java.util.Optional; /** * Repository for managing ClusterEntity persistence and lookups. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites */ public interface ClusterRepository { /** @@ -92,5 +98,5 @@ public interface ClusterRepository { /** * Update world for clusters overlapping the given bounds in oldWorld. */ - void replaceWorldInBounds(String oldWorld, String newWorld, com.plotsquared.core.plot.PlotId min, com.plotsquared.core.plot.PlotId max); + void replaceWorldInBounds(String oldWorld, String newWorld, PlotId min, PlotId max); } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterSettingsRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterSettingsRepository.java index fdb3392b76..53eb44b2e9 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterSettingsRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterSettingsRepository.java @@ -24,6 +24,11 @@ /** * Repository abstraction for managing cluster settings operations. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites */ public interface ClusterSettingsRepository { /** diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlayerMetaRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlayerMetaRepository.java index d5857b4361..99e13c190c 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlayerMetaRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlayerMetaRepository.java @@ -25,6 +25,11 @@ /** * Repository for storing and retrieving arbitrary metadata entries for players. * Keys are namespaced per player UUID and map to binary values. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites */ public interface PlayerMetaRepository { /** diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotCommentRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotCommentRepository.java index 47eb6d794b..2b117fa815 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotCommentRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotCommentRepository.java @@ -26,6 +26,11 @@ * Repository for managing plot comments, typically grouped by "inbox" names * (e.g., inbox types). Methods support querying by world, by plot hash, and * by inbox, as well as adding and removing comments. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites */ public interface PlotCommentRepository { /** diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotDeniedRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotDeniedRepository.java index d10d05baa1..e3f3eb9773 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotDeniedRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotDeniedRepository.java @@ -25,6 +25,11 @@ * Denied users are explicitly prevented from interacting with or entering the plot * depending on gameplay rules. This repository stores associations between plot ids * and player UUIDs. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites */ public interface PlotDeniedRepository { /** diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotFlagRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotFlagRepository.java index 2cc6baf297..cb9431c57e 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotFlagRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotFlagRepository.java @@ -26,6 +26,11 @@ /** * Repository for managing flags associated with a plot. * A flag is a named configuration entry applied to an individual plot. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites */ public interface PlotFlagRepository { /** diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotMembershipRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotMembershipRepository.java index d50347e747..2066eac740 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotMembershipRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotMembershipRepository.java @@ -23,6 +23,11 @@ /** * Repository for managing plot member associations. * Members typically have elevated permissions on the plot compared to visitors. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites */ public interface PlotMembershipRepository { /** diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRatingRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRatingRepository.java index a35f9ccb8f..cabb98356f 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRatingRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRatingRepository.java @@ -24,6 +24,11 @@ /** * Repository for managing player ratings of plots. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites */ public interface PlotRatingRepository { /** diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java index 58c5e2eaf9..da2ad645db 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java @@ -28,6 +28,11 @@ /** * Repository abstraction for reading and writing plot data and related * lookups by id, world, owner, and coordinates. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites */ public interface PlotRepository { /** diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotSettingsRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotSettingsRepository.java index 494023e2f2..34f51e011a 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotSettingsRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotSettingsRepository.java @@ -24,6 +24,11 @@ /** * Repository for persisting and retrieving per-plot settings. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites */ public interface PlotSettingsRepository { /** diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotTrustedRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotTrustedRepository.java index 363cb42216..79c48217b2 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotTrustedRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotTrustedRepository.java @@ -24,6 +24,11 @@ * Repository for managing trusted users for a plot. * Trusted users typically have broader permissions than helpers but may be * distinct from owners and members depending on server policy. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites */ public interface PlotTrustedRepository { /** diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/package-info.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/package-info.java new file mode 100644 index 0000000000..c18d74e7b8 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/package-info.java @@ -0,0 +1,12 @@ +/** + * This package contains interfaces for repositories that handle data persistence for various entities in the PlotSquared system. + * + * @version 1.0.0 + * @since 8.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +@NotNullByDefault +package com.plotsquared.core.persistence.repository.api; + +import org.jetbrains.annotations.NotNullByDefault; From 5f98a88c8255940a568c358ebcc8e9dffa0a3e55 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 09:47:44 +0200 Subject: [PATCH 058/141] feat: enhance ClusterEntity and ClusterRepositoryJpa with additional named queries and improve method signatures for better type safety --- .../persistence/entity/ClusterEntity.java | 13 +++- .../repository/jpa/ClusterRepositoryJpa.java | 78 ++++++++++--------- 2 files changed, 50 insertions(+), 41 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterEntity.java index fd98081862..bc5337753e 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterEntity.java @@ -27,10 +27,17 @@ import jakarta.persistence.NamedQuery; import jakarta.persistence.Table; +import java.sql.Timestamp; + @Entity @Table(name = "cluster") @NamedQueries({ - @NamedQuery(name = "Cluster.findByWorldAndBounds", query = "SELECT c FROM ClusterEntity c WHERE c.world = :world AND c.pos1X <= :x AND c.pos2X >= :x AND c.pos1Z <= :z AND c.pos2Z >= :z") + @NamedQuery(name = "Cluster.findByWorldAndBounds", query = "SELECT c FROM ClusterEntity c WHERE c.world = :world AND c" + + ".pos1X <= :x AND c.pos2X >= :x AND c.pos1Z <= :z AND c.pos2Z >= :z"), + @NamedQuery(name = "Cluster.findByWorld", query = "SELECT c FROM ClusterEntity c WHERE c.world = :world"), + @NamedQuery(name = "Cluster.finaAll", query = "SELECT c FROM ClusterEntity c"), + @NamedQuery(name = "Cluster.updateWorld", query = "UPDATE ClusterEntity c SET c.world = :newWorld WHERE c.world = :oldWorld"), + @NamedQuery(name = "Cluster.updateWorldInBounds", query = "UPDATE ClusterEntity c SET c.world = :newWorld WHERE c.world = :oldWorld AND c.pos1X <= :maxX AND c.pos1Z <= :maxZ AND c.pos2X >= :minX AND c.pos2Z >= :minZ") }) public class ClusterEntity { @Id @@ -43,7 +50,7 @@ public class ClusterEntity { @Column(length = 40) private String owner; @Column(length = 45) private String world; @Column(name = "timestamp", insertable = false, updatable = false) - private java.sql.Timestamp timestamp; + private Timestamp timestamp; public ClusterEntity() {} @@ -62,5 +69,5 @@ public ClusterEntity() {} public String getWorld() { return world; } public void setWorld(String world) { this.world = world; } public java.sql.Timestamp getTimestamp() { return timestamp; } - public void setTimestamp(java.sql.Timestamp timestamp) { this.timestamp = timestamp; } + public void setTimestamp(Timestamp timestamp) { this.timestamp = timestamp; } } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterRepositoryJpa.java index 3925a952c5..37a3d1d4ee 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterRepositoryJpa.java @@ -21,11 +21,13 @@ import com.google.inject.Inject; import com.plotsquared.core.persistence.entity.ClusterEntity; import com.plotsquared.core.persistence.repository.api.ClusterRepository; +import com.plotsquared.core.plot.PlotId; import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManagerFactory; import jakarta.persistence.EntityTransaction; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; import java.util.List; import java.util.Optional; @@ -42,49 +44,45 @@ public ClusterRepositoryJpa(EntityManagerFactory emf) { } @Override - public Optional findById(long id) { - EntityManager em = emf.createEntityManager(); - try { + public @NotNull Optional findById(long id) { + try (EntityManager em = emf.createEntityManager()) { return Optional.ofNullable(em.find(ClusterEntity.class, id)); - } finally { em.close(); } + } } @Override - public Optional findByWorldAndBounds(String world, int x, int z) { - EntityManager em = emf.createEntityManager(); - try { + public @NotNull Optional findByWorldAndBounds(@NotNull String world, int x, int z) { + try (EntityManager em = emf.createEntityManager()) { return em.createNamedQuery("Cluster.findByWorldAndBounds", ClusterEntity.class) .setParameter("world", world) .setParameter("x", x) .setParameter("z", z) .getResultStream().findFirst(); - } finally { em.close(); } + } } @Override - public List findByWorld(String world) { - EntityManager em = emf.createEntityManager(); - try { - return em.createQuery("SELECT c FROM ClusterEntity c WHERE c.world = :world", ClusterEntity.class) + public @NotNull List findByWorld(@NotNull String world) { + try (EntityManager em = emf.createEntityManager()) { + return em.createNamedQuery("Cluster.findByWorld", ClusterEntity.class) .setParameter("world", world) .getResultList(); - } finally { em.close(); } + } } @Override - public List findAll() { - EntityManager em = emf.createEntityManager(); - try { - return em.createQuery("SELECT c FROM ClusterEntity c", ClusterEntity.class) + public @NotNull List findAll() { + try (EntityManager em = emf.createEntityManager()) { + return em.createNamedQuery("Cluster.finaAll", ClusterEntity.class) .getResultList(); - } finally { em.close(); } + } } @Override - public void save(ClusterEntity cluster) { + public void save(@NotNull ClusterEntity cluster) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); if (cluster.getId() == null) { em.persist(cluster); @@ -95,15 +93,14 @@ public void save(ClusterEntity cluster) { } catch (RuntimeException ex) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to save cluster (id={}, world={})", cluster.getId(), cluster.getWorld(), ex); - throw ex; - } finally { em.close(); } + } } @Override public void deleteById(long id) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); ClusterEntity e = em.find(ClusterEntity.class, id); if (e != null) { @@ -113,17 +110,16 @@ public void deleteById(long id) { } catch (RuntimeException ex) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to delete cluster by id (id={})", id, ex); - throw ex; - } finally { em.close(); } + } } @Override - public void updateWorldAll(String oldWorld, String newWorld) { + public void updateWorldAll(@NotNull String oldWorld, @NotNull String newWorld) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); - em.createQuery("UPDATE ClusterEntity c SET c.world = :newWorld WHERE c.world = :oldWorld") + em.createNamedQuery("Cluster.updateWorld") .setParameter("newWorld", newWorld) .setParameter("oldWorld", oldWorld) .executeUpdate(); @@ -131,17 +127,16 @@ public void updateWorldAll(String oldWorld, String newWorld) { } catch (RuntimeException ex) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to update cluster world (all) oldWorld={}, newWorld={}", oldWorld, newWorld, ex); - throw ex; - } finally { em.close(); } + } } @Override - public void updateWorldInBounds(String oldWorld, String newWorld, int minX, int minZ, int maxX, int maxZ) { + public void updateWorldInBounds(@NotNull String oldWorld, @NotNull String newWorld, int minX, int minZ, int maxX, int maxZ) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); - em.createQuery("UPDATE ClusterEntity c SET c.world = :newWorld WHERE c.world = :oldWorld AND c.pos1X <= :maxX AND c.pos1Z <= :maxZ AND c.pos2X >= :minX AND c.pos2Z >= :minZ") + em.createNamedQuery("Cluster.updateWorldInBounds") .setParameter("newWorld", newWorld) .setParameter("oldWorld", oldWorld) .setParameter("minX", minX) @@ -152,9 +147,17 @@ public void updateWorldInBounds(String oldWorld, String newWorld, int minX, int tx.commit(); } catch (RuntimeException ex) { if (tx.isActive()) tx.rollback(); - LOGGER.error("Failed to update cluster world in bounds oldWorld={}, newWorld={}, bounds=[{}..{}]x[{}..{}]", oldWorld, newWorld, minX, maxX, minZ, maxZ, ex); - throw ex; - } finally { em.close(); } + LOGGER.error( + "Failed to update cluster world in bounds oldWorld={}, newWorld={}, bounds=[{}..{}]x[{}..{}]", + oldWorld, + newWorld, + minX, + maxX, + minZ, + maxZ, + ex + ); + } } @Override @@ -163,8 +166,7 @@ public void replaceWorld(String oldWorld, String newWorld) { } @Override - public void replaceWorldInBounds(String oldWorld, String newWorld, com.plotsquared.core.plot.PlotId min, com.plotsquared.core.plot.PlotId max) { - if (min == null || max == null) return; + public void replaceWorldInBounds(String oldWorld, String newWorld, PlotId min, PlotId max) { updateWorldInBounds(oldWorld, newWorld, min.getX(), min.getY(), max.getX(), max.getY()); } } From b2f68e22e48b652b1968c2cb93841d06cffdb0ce Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 09:48:06 +0200 Subject: [PATCH 059/141] feat: refactor ClusterHelperRepositoryJpa to use try-with-resources for EntityManager management --- .../jpa/ClusterHelperRepositoryJpa.java | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterHelperRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterHelperRepositoryJpa.java index 3e734c5cb3..6ad94553a6 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterHelperRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterHelperRepositoryJpa.java @@ -42,13 +42,10 @@ public ClusterHelperRepositoryJpa(EntityManagerFactory emf) { @Override public List findUsers(long clusterId) { - EntityManager em = emf.createEntityManager(); - try { + try (EntityManager em = emf.createEntityManager()) { return em.createNamedQuery("ClusterHelper.findUsers", String.class) .setParameter("clusterId", clusterId) .getResultList(); - } finally { - em.close(); } } @@ -56,7 +53,7 @@ public List findUsers(long clusterId) { public void add(long clusterId, String userUuid) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); ClusterHelperEntity e = new ClusterHelperEntity(); e.setClusterId(clusterId); @@ -66,9 +63,6 @@ public void add(long clusterId, String userUuid) { } catch (RuntimeException ex) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to add cluster helper (clusterId={}, userUuid={})", clusterId, userUuid, ex); - throw ex; - } finally { - em.close(); } } @@ -76,7 +70,7 @@ public void add(long clusterId, String userUuid) { public void remove(long clusterId, String userUuid) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); em.createNamedQuery("ClusterHelper.delete") .setParameter("clusterId", clusterId) @@ -86,9 +80,6 @@ public void remove(long clusterId, String userUuid) { } catch (RuntimeException ex) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to remove cluster helper (clusterId={}, userUuid={})", clusterId, userUuid, ex); - throw ex; - } finally { - em.close(); } } } From ed5a97315453c35070286dfebbf099b6c24b8a12 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 09:48:12 +0200 Subject: [PATCH 060/141] feat: refactor ClusterInvitedRepositoryJpa to use try-with-resources for EntityManager management --- .../jpa/ClusterInvitedRepositoryJpa.java | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterInvitedRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterInvitedRepositoryJpa.java index 85bd1cfb69..849ef36ab3 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterInvitedRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterInvitedRepositoryJpa.java @@ -42,13 +42,10 @@ public ClusterInvitedRepositoryJpa(EntityManagerFactory emf) { @Override public List findUsers(long clusterId) { - EntityManager em = emf.createEntityManager(); - try { + try (EntityManager em = emf.createEntityManager()) { return em.createNamedQuery("ClusterInvited.findUsers", String.class) .setParameter("clusterId", clusterId) .getResultList(); - } finally { - em.close(); } } @@ -56,7 +53,7 @@ public List findUsers(long clusterId) { public void add(long clusterId, String userUuid) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); ClusterInvitedEntity e = new ClusterInvitedEntity(); e.setClusterId(clusterId); @@ -66,9 +63,6 @@ public void add(long clusterId, String userUuid) { } catch (RuntimeException ex) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to add cluster invited (clusterId={}, userUuid={})", clusterId, userUuid, ex); - throw ex; - } finally { - em.close(); } } @@ -76,7 +70,7 @@ public void add(long clusterId, String userUuid) { public void remove(long clusterId, String userUuid) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); em.createNamedQuery("ClusterInvited.delete") .setParameter("clusterId", clusterId) @@ -86,9 +80,6 @@ public void remove(long clusterId, String userUuid) { } catch (RuntimeException ex) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to remove cluster invited (clusterId={}, userUuid={})", clusterId, userUuid, ex); - throw ex; - } finally { - em.close(); } } } From 300612dbdd92097279a835f4cc846b3244ca1fc9 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 09:48:19 +0200 Subject: [PATCH 061/141] feat: refactor DBFunc to eliminate unnecessary try-catch blocks and improve readability --- .../com/plotsquared/core/database/DBFunc.java | 108 ++++++++---------- 1 file changed, 49 insertions(+), 59 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java index 9d374e244b..f10afabf9d 100644 --- a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java +++ b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java @@ -753,46 +753,42 @@ public static void setRating(Plot plot, UUID rater, int value) { public static HashMap> getClusters() { HashMap> result = new HashMap<>(); - try { - ClusterRepository clusterRepo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); - ClusterHelperRepository helperRepo = PlotSquared.platform().injector().getInstance(ClusterHelperRepository.class); - ClusterInvitedRepository invitedRepo = PlotSquared.platform().injector().getInstance(ClusterInvitedRepository.class); - ClusterSettingsRepository settingsRepo = PlotSquared.platform().injector().getInstance(ClusterSettingsRepository.class); - List clusters = clusterRepo.findAll(); - Map built = new HashMap<>(); - for (ClusterEntity ce : clusters) { - UUID owner = null; - try { owner = ce.getOwner() != null ? UUID.fromString(ce.getOwner()) : null; } catch (IllegalArgumentException ignored) {} - PlotCluster cluster = new PlotCluster(null, PlotId.of(ce.getPos1X(), ce.getPos1Z()), PlotId.of(ce.getPos2X(), ce.getPos2Z()), owner); - built.put(ce.getId(), cluster); - result.computeIfAbsent(ce.getWorld(), k -> new java.util.HashSet<>()).add(cluster); + ClusterRepository clusterRepo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); + ClusterHelperRepository helperRepo = PlotSquared.platform().injector().getInstance(ClusterHelperRepository.class); + ClusterInvitedRepository invitedRepo = PlotSquared.platform().injector().getInstance(ClusterInvitedRepository.class); + ClusterSettingsRepository settingsRepo = PlotSquared.platform().injector().getInstance(ClusterSettingsRepository.class); + List clusters = clusterRepo.findAll(); + Map built = new HashMap<>(); + for (ClusterEntity ce : clusters) { + UUID owner = Optional.ofNullable(ce.getOwner()).map(UUID::fromString).orElse(null); + PlotCluster cluster = new PlotCluster(null, PlotId.of(ce.getPos1X(), ce.getPos1Z()), PlotId.of(ce.getPos2X(), ce.getPos2Z()), owner); + built.put(ce.getId(), cluster); + result.computeIfAbsent(ce.getWorld(), k -> new java.util.HashSet<>()).add(cluster); + } + // Populate helpers and invited + for (Map.Entry e : built.entrySet()) { + long id = e.getKey(); + PlotCluster cluster = e.getValue(); + for (String u : helperRepo.findUsers(id)) { + cluster.helpers.add(UUID.fromString(u)); } - // Populate helpers and invited - for (Map.Entry e : built.entrySet()) { - long id = e.getKey(); - PlotCluster cluster = e.getValue(); - for (String u : helperRepo.findUsers(id)) { - try { cluster.helpers.add(UUID.fromString(u)); } catch (IllegalArgumentException ignored) {} - } - for (String u : invitedRepo.findUsers(id)) { - try { cluster.invited.add(UUID.fromString(u)); } catch (IllegalArgumentException ignored) {} + for (String u : invitedRepo.findUsers(id)) { + cluster.invited.add(UUID.fromString(u)); + } + // Apply settings (alias, merged). Avoid setting temp variable. + settingsRepo.findById(id).ifPresent(se -> { + if (se.getAlias() != null) { + cluster.settings.setAlias(se.getAlias()); } - // Apply settings (alias, merged). Avoid setting temp variable. - settingsRepo.findById(id).ifPresent(se -> { - if (se.getAlias() != null) { - cluster.settings.setAlias(se.getAlias()); - } - Integer m = se.getMerged(); - if (m != null) { - boolean[] merged = new boolean[4]; - for (int i = 0; i < 4; i++) { - merged[3 - i] = (m & 1 << i) != 0; - } - cluster.settings.setMerged(merged); + Integer m = se.getMerged(); + if (m != null) { + boolean[] merged = new boolean[4]; + for (int i = 0; i < 4; i++) { + merged[3 - i] = (m & 1 << i) != 0; } - }); - } - } catch (Throwable ignored) { + cluster.settings.setMerged(merged); + } + }); } return result; } @@ -801,32 +797,26 @@ public static void setPosition(PlotCluster cluster, String position) { if (cluster == null || position == null) { return; } - try { - ClusterRepository clusterRepo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); - ClusterSettingsRepository settingsRepo = PlotSquared.platform().injector().getInstance(ClusterSettingsRepository.class); - String world = cluster.area != null ? cluster.area.getWorldName() : null; - if (world == null) { - return; - } - PlotId center = cluster.getCenterPlotId(); - java.util.Optional ce = clusterRepo.findByWorldAndBounds(world, center.getX(), center.getY()); - ce.ifPresent(entity -> settingsRepo.updatePosition(entity.getId(), position)); - } catch (Throwable ignored) { + ClusterRepository clusterRepo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); + ClusterSettingsRepository settingsRepo = PlotSquared.platform().injector().getInstance(ClusterSettingsRepository.class); + String world = cluster.area != null ? cluster.area.getWorldName() : null; + if (world == null) { + return; } + PlotId center = cluster.getCenterPlotId(); + Optional ce = clusterRepo.findByWorldAndBounds(world, center.getX(), center.getY()); + ce.ifPresent(entity -> settingsRepo.updatePosition(entity.getId(), position)); } public static void replaceWorld(String oldWorld, String newWorld, PlotId min, PlotId max) { - try { - PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - ClusterRepository clusterRepo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); - if (min == null) { - plotRepo.replaceWorld(oldWorld, newWorld); - clusterRepo.replaceWorld(oldWorld, newWorld); - } else { - plotRepo.replaceWorldInBounds(oldWorld, newWorld, min, max); - clusterRepo.replaceWorldInBounds(oldWorld, newWorld, min, max); - } - } catch (Throwable ignored) { + PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + ClusterRepository clusterRepo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); + if (min == null) { + plotRepo.replaceWorld(oldWorld, newWorld); + clusterRepo.replaceWorld(oldWorld, newWorld); + } else { + plotRepo.replaceWorldInBounds(oldWorld, newWorld, min, max); + clusterRepo.replaceWorldInBounds(oldWorld, newWorld, min, max); } } From a5d7cc77078d91498ede404de937a1e016da412f Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 09:50:21 +0200 Subject: [PATCH 062/141] feat: add new methods to PlotRepository for world name replacement, plot movement, and owner assignment --- .../repository/api/PlotRepository.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java index da2ad645db..56a1a95aa2 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java @@ -46,10 +46,28 @@ public interface PlotRepository { */ boolean swapPlots(Plot plot1, Plot plot2); + /** + * Updates the world name for all stored plots. + * + * @param oldWorld The previous world name + * @param newWorld The new world name + */ void replaceWorldAll(String oldWorld, String newWorld); + /** + * Moves all data from one plot to another. + * + * @param originPlot The source plot + * @param newPlot The target plot + */ void movePlots(Plot originPlot, Plot newPlot); + /** + * Sets a new owner for a plot. + * + * @param plot The plot whose owner should be changed + * @param newOwner The UUID of the new owner + */ void setOwner(Plot plot, UUID newOwner); /** From 9cf43c1eb9665ccf8f2827f0dd3218ec895469f3 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 09:54:02 +0200 Subject: [PATCH 063/141] feat: update classes for improved readability and consistency, add Javadoc annotations for versioning --- .../persistence/config/FlywayBootstrap.java | 8 +++-- .../config/JpaPropertiesProvider.java | 7 +++- .../persistence/config/PersistenceModule.java | 34 ++++++++++++------- .../config/PrefixedNamingStrategy.java | 14 ++++++-- 4 files changed, 45 insertions(+), 18 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/FlywayBootstrap.java b/Core/src/main/java/com/plotsquared/core/persistence/config/FlywayBootstrap.java index a3831e4813..42aae38c71 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/FlywayBootstrap.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/FlywayBootstrap.java @@ -26,9 +26,14 @@ /** * Eager bootstrap that executes Flyway migrations during application startup. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites */ @Singleton -public class FlywayBootstrap { +public final class FlywayBootstrap { private static final Logger LOGGER = Logger.getLogger(FlywayBootstrap.class.getName()); @Inject @@ -38,7 +43,6 @@ public FlywayBootstrap(Flyway flyway) { LOGGER.info("Flyway migration complete."); } catch (Exception e) { LOGGER.severe("Flyway migration failed: " + e.getMessage()); - throw e; } } } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java b/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java index 75ad622b34..210c12228d 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java @@ -26,9 +26,14 @@ /** * Builds JPA/Hibernate properties based on Storage configuration. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites */ @Singleton -public class JpaPropertiesProvider { +public final class JpaPropertiesProvider { /** * Create a map of JPA properties suitable for EntityManagerFactory creation. diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java b/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java index 68f6ff7ce4..6de6b75cff 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java @@ -56,7 +56,15 @@ import java.util.Map; import java.util.function.Supplier; -public class PersistenceModule extends AbstractModule { +/** + * Guice module for configuring persistence-related bindings and providers. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +public final class PersistenceModule extends AbstractModule { @Override protected void configure() { @@ -88,18 +96,6 @@ EntityManagerFactory provideEmf(JpaPropertiesProvider jpaPropertiesProvider) { } - private T syncThreadForServiceLoader(Supplier supplier) { - Thread currentThread = Thread.currentThread(); - ClassLoader originalClassLoader = currentThread.getContextClassLoader(); - ClassLoader pluginClassLoader = this.getClass().getClassLoader(); - try { - currentThread.setContextClassLoader(pluginClassLoader); - return supplier.get(); - } finally { - currentThread.setContextClassLoader(originalClassLoader); - } - } - @Provides EntityManager provideEm(EntityManagerFactory emf) { return emf.createEntityManager(); @@ -137,4 +133,16 @@ Flyway provideFlyway() { .placeholders(placeholders) .load(); } + + private T syncThreadForServiceLoader(Supplier supplier) { + Thread currentThread = Thread.currentThread(); + ClassLoader originalClassLoader = currentThread.getContextClassLoader(); + ClassLoader pluginClassLoader = this.getClass().getClassLoader(); + try { + currentThread.setContextClassLoader(pluginClassLoader); + return supplier.get(); + } finally { + currentThread.setContextClassLoader(originalClassLoader); + } + } } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/PrefixedNamingStrategy.java b/Core/src/main/java/com/plotsquared/core/persistence/config/PrefixedNamingStrategy.java index 95fb6291e0..e8075cf42a 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/PrefixedNamingStrategy.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/PrefixedNamingStrategy.java @@ -21,13 +21,23 @@ import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.naming.PhysicalNamingStrategy; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; +import org.jetbrains.annotations.NotNull; +/** + * A PhysicalNamingStrategy that adds a specified prefix to all table names. + * This is useful for avoiding naming conflicts in shared databases. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ public class PrefixedNamingStrategy implements PhysicalNamingStrategy { private final String prefix; - public PrefixedNamingStrategy(String prefix) { - this.prefix = prefix == null ? "" : prefix; + public PrefixedNamingStrategy(@NotNull String prefix) { + this.prefix = prefix; } @Override From 7470b019f7438960d32ed756e7303f3e855f30f6 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 09:55:09 +0200 Subject: [PATCH 064/141] feat: refactor PlayerMetaRepositoryJpa to use try-with-resources for EntityManager management --- .../jpa/PlayerMetaRepositoryJpa.java | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlayerMetaRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlayerMetaRepositoryJpa.java index 622bdff529..6b12b641c4 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlayerMetaRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlayerMetaRepositoryJpa.java @@ -42,13 +42,10 @@ public PlayerMetaRepositoryJpa(EntityManagerFactory emf) { @Override public List findByUuid(String uuid) { - EntityManager em = emf.createEntityManager(); - try { + try (EntityManager em = emf.createEntityManager()) { return em.createNamedQuery("PlayerMeta.findByUuid", PlayerMetaEntity.class) .setParameter("uuid", uuid) .getResultList(); - } finally { - em.close(); } } @@ -56,7 +53,7 @@ public List findByUuid(String uuid) { public void put(String uuid, String key, byte[] value) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); // Delete existing row for same (uuid,key) then insert new em.createNamedQuery("PlayerMeta.deleteByUuidAndKey") @@ -71,10 +68,13 @@ public void put(String uuid, String key, byte[] value) { tx.commit(); } catch (RuntimeException ex) { if (tx.isActive()) tx.rollback(); - LOGGER.error("Failed to put player meta (uuid={}, key={}, value.length={})", uuid, key, value != null ? value.length : null, ex); - throw ex; - } finally { - em.close(); + LOGGER.error( + "Failed to put player meta (uuid={}, key={}, value.length={})", + uuid, + key, + value != null ? value.length : null, + ex + ); } } @@ -82,7 +82,7 @@ public void put(String uuid, String key, byte[] value) { public void delete(String uuid, String key) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); em.createNamedQuery("PlayerMeta.deleteByUuidAndKey") .setParameter("uuid", uuid) @@ -92,9 +92,6 @@ public void delete(String uuid, String key) { } catch (RuntimeException ex) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to delete player meta (uuid={}, key={})", uuid, key, ex); - throw ex; - } finally { - em.close(); } } } From 15790dd7bcf6de55e977f3a094d2c7dbbf0116cd Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 09:55:38 +0200 Subject: [PATCH 065/141] feat: refactor ClusterSettingsRepositoryJpa to use try-with-resources for EntityManager management --- .../repository/jpa/ClusterSettingsRepositoryJpa.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterSettingsRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterSettingsRepositoryJpa.java index 2f229bfde8..2a96ee7e06 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterSettingsRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterSettingsRepositoryJpa.java @@ -42,11 +42,8 @@ public ClusterSettingsRepositoryJpa(EntityManagerFactory emf) { @Override public Optional findById(long clusterId) { - EntityManager em = emf.createEntityManager(); - try { + try (EntityManager em = emf.createEntityManager()) { return Optional.ofNullable(em.find(ClusterSettingsEntity.class, clusterId)); - } finally { - em.close(); } } @@ -54,7 +51,7 @@ public Optional findById(long clusterId) { public void updatePosition(long clusterId, String position) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); em.createNamedQuery("ClusterSettings.updatePosition") .setParameter("clusterId", clusterId) @@ -64,9 +61,6 @@ public void updatePosition(long clusterId, String position) { } catch (RuntimeException ex) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to update cluster position (clusterId={}, position={})", clusterId, position, ex); - throw ex; - } finally { - em.close(); } } } From 6e74200cdd32e4569db3130c563719e7c0c452ee Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 09:56:21 +0200 Subject: [PATCH 066/141] feat: enhance PlayerMetaRepositoryJpa with @NotNull annotations for improved null safety --- .../repository/jpa/PlayerMetaRepositoryJpa.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlayerMetaRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlayerMetaRepositoryJpa.java index 6b12b641c4..d3825491a1 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlayerMetaRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlayerMetaRepositoryJpa.java @@ -26,6 +26,7 @@ import jakarta.persistence.EntityTransaction; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; import java.util.List; @@ -41,7 +42,7 @@ public PlayerMetaRepositoryJpa(EntityManagerFactory emf) { } @Override - public List findByUuid(String uuid) { + public @NotNull List findByUuid(@NotNull String uuid) { try (EntityManager em = emf.createEntityManager()) { return em.createNamedQuery("PlayerMeta.findByUuid", PlayerMetaEntity.class) .setParameter("uuid", uuid) @@ -50,7 +51,7 @@ public List findByUuid(String uuid) { } @Override - public void put(String uuid, String key, byte[] value) { + public void put(@NotNull String uuid, @NotNull String key, byte @NotNull [] value) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); try (em) { @@ -72,14 +73,14 @@ public void put(String uuid, String key, byte[] value) { "Failed to put player meta (uuid={}, key={}, value.length={})", uuid, key, - value != null ? value.length : null, + value.length, ex ); } } @Override - public void delete(String uuid, String key) { + public void delete(@NotNull String uuid, @NotNull String key) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); try (em) { From 68832572219776ed11137a84ac2777928fb05c2b Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 09:56:37 +0200 Subject: [PATCH 067/141] feat: add @NotNull annotation to updatePosition method in ClusterSettingsRepositoryJpa for improved null safety --- .../repository/jpa/ClusterSettingsRepositoryJpa.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterSettingsRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterSettingsRepositoryJpa.java index 2a96ee7e06..818d5df593 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterSettingsRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterSettingsRepositoryJpa.java @@ -26,6 +26,7 @@ import jakarta.persistence.EntityTransaction; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; import java.util.Optional; @@ -48,7 +49,7 @@ public Optional findById(long clusterId) { } @Override - public void updatePosition(long clusterId, String position) { + public void updatePosition(long clusterId, @NotNull String position) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); try (em) { From 7df59b5e48ae100a0ca2a27fdd2912387a472274 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 09:58:16 +0200 Subject: [PATCH 068/141] feat: add @NotNull annotations to PlotCommentRepositoryJpa methods for improved null safety and refactor EntityManager management --- .../jpa/PlotCommentRepositoryJpa.java | 63 +++++++++---------- 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotCommentRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotCommentRepositoryJpa.java index 2a4e733235..dce6da2ca0 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotCommentRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotCommentRepositoryJpa.java @@ -26,6 +26,7 @@ import jakarta.persistence.EntityTransaction; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; import java.util.List; @@ -41,20 +42,17 @@ public PlotCommentRepositoryJpa(EntityManagerFactory emf) { } @Override - public List findByWorldAndInbox(String world, String inbox) { - EntityManager em = emf.createEntityManager(); - try { + public List findByWorldAndInbox(@NotNull String world, @NotNull String inbox) { + try (EntityManager em = emf.createEntityManager()) { return em.createNamedQuery("PlotComment.findByWorldAndInbox", PlotCommentEntity.class) .setParameter("world", world) .setParameter("inbox", inbox) .getResultList(); - } finally { - em.close(); } } @Override - public List findByWorldHashAndInbox(String world, int hashcode, String inbox) { + public List findByWorldHashAndInbox(@NotNull String world, int hashcode, @NotNull String inbox) { EntityManager em = emf.createEntityManager(); try { return em.createNamedQuery("PlotComment.findByWorldHashAndInbox", PlotCommentEntity.class) @@ -68,27 +66,30 @@ public List findByWorldHashAndInbox(String world, int hashcod } @Override - public void save(PlotCommentEntity entity) { + public void save(@NotNull PlotCommentEntity entity) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); em.persist(entity); tx.commit(); } catch (RuntimeException e) { if (tx.isActive()) tx.rollback(); - LOGGER.error("Failed to save plot comment (world={}, inbox={}, hashcode={})", entity.getWorld(), entity.getInbox(), entity.getHashcode(), e); - throw e; - } finally { - em.close(); + LOGGER.error( + "Failed to save plot comment (world={}, inbox={}, hashcode={})", + entity.getWorld(), + entity.getInbox(), + entity.getHashcode(), + e + ); } } @Override - public void deleteOne(String world, int hashcode, String inbox, String sender, String comment) { + public void deleteOne(@NotNull String world, int hashcode, @NotNull String inbox, @NotNull String sender, @NotNull String comment) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); em.createNamedQuery("PlotComment.deleteOne") .setParameter("world", world) @@ -100,18 +101,23 @@ public void deleteOne(String world, int hashcode, String inbox, String sender, S tx.commit(); } catch (RuntimeException e) { if (tx.isActive()) tx.rollback(); - LOGGER.error("Failed to delete one plot comment (world={}, inbox={}, hashcode={}, sender={}, comment={})", world, inbox, hashcode, sender, comment, e); - throw e; - } finally { - em.close(); + LOGGER.error( + "Failed to delete one plot comment (world={}, inbox={}, hashcode={}, sender={}, comment={})", + world, + inbox, + hashcode, + sender, + comment, + e + ); } } @Override - public void clearInbox(String world, String inbox) { + public void clearInbox(@NotNull String world, @NotNull String inbox) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); em.createNamedQuery("PlotComment.clearInbox") .setParameter("world", world) @@ -121,17 +127,14 @@ public void clearInbox(String world, String inbox) { } catch (RuntimeException e) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to clear inbox (world={}, inbox={})", world, inbox, e); - throw e; - } finally { - em.close(); } } @Override - public void clearInbox(String world, int hashcode, String inbox) { + public void clearInbox(@NotNull String world, int hashcode, @NotNull String inbox) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); em.createNamedQuery("PlotComment.clearInboxByWorldHash") .setParameter("world", world) @@ -142,17 +145,14 @@ public void clearInbox(String world, int hashcode, String inbox) { } catch (RuntimeException e) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to clear inbox by world+hash (world={}, hashcode={}, inbox={})", world, hashcode, inbox, e); - throw e; - } finally { - em.close(); } } @Override - public void deleteByWorldAndHash(String world, int hashcode) { + public void deleteByWorldAndHash(@NotNull String world, int hashcode) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); em.createNamedQuery("PlotComment.deleteByWorldAndHash") .setParameter("world", world) @@ -162,9 +162,6 @@ public void deleteByWorldAndHash(String world, int hashcode) { } catch (RuntimeException e) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to delete comments by world and hash (world={}, hashcode={})", world, hashcode, e); - throw e; - } finally { - em.close(); } } } From 253c6a951eb3ece4e37627c0ac4778967bc24f29 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 10:00:05 +0200 Subject: [PATCH 069/141] feat: add @NotNull annotations to methods in PlotDeniedRepositoryJpa for improved null safety and refactor EntityManager management --- .../persistence/entity/PlotDeniedEntity.java | 3 +- .../jpa/PlotDeniedRepositoryJpa.java | 29 +++++++++---------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotDeniedEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotDeniedEntity.java index 9ff854e773..f3589a81ee 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotDeniedEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotDeniedEntity.java @@ -32,7 +32,8 @@ @NamedQueries({ @NamedQuery(name = "PlotDenied.delete", query = "DELETE FROM PlotDeniedEntity e WHERE e.plotId = :plotId AND e.userUuid = :uuid"), @NamedQuery(name = "PlotDenied.findUsers", query = "SELECT e.userUuid FROM PlotDeniedEntity e WHERE e.plotId = :plotId"), - @NamedQuery(name = "PlotDenied.deleteAll", query = "DELETE FROM PlotDeniedEntity e WHERE e.plotId = :plotId") + @NamedQuery(name = "PlotDenied.deleteAll", query = "DELETE FROM PlotDeniedEntity e WHERE e.plotId = :plotId"), + @NamedQuery(name = "PlotDenied.deleteByPlotId", query = "DELETE FROM PlotDeniedEntity e WHERE e.plotId = :plotId") }) public class PlotDeniedEntity { @Id diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotDeniedRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotDeniedRepositoryJpa.java index 8748f677b8..50e3f7b0bc 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotDeniedRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotDeniedRepositoryJpa.java @@ -26,6 +26,7 @@ import jakarta.persistence.EntityTransaction; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; import java.util.List; @@ -41,20 +42,19 @@ public PlotDeniedRepositoryJpa(EntityManagerFactory emf) { } @Override - public List findUsers(long plotId) { - EntityManager em = emf.createEntityManager(); - try { + public @NotNull List findUsers(long plotId) { + try (EntityManager em = emf.createEntityManager()) { return em.createNamedQuery("PlotDenied.findUsers", String.class) .setParameter("plotId", plotId) .getResultList(); - } finally { em.close(); } + } } @Override - public void add(long plotId, String userUuid) { + public void add(long plotId, @NotNull String userUuid) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); PlotDeniedEntity e = new PlotDeniedEntity(); e.setPlotId(plotId); @@ -64,15 +64,14 @@ public void add(long plotId, String userUuid) { } catch (RuntimeException ex) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to add plot denied (plotId={}, userUuid={})", plotId, userUuid, ex); - throw ex; - } finally { em.close(); } + } } @Override - public void remove(long plotId, String userUuid) { + public void remove(long plotId, @NotNull String userUuid) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); em.createNamedQuery("PlotDenied.delete") .setParameter("plotId", plotId) @@ -82,24 +81,22 @@ public void remove(long plotId, String userUuid) { } catch (RuntimeException ex) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to remove plot denied (plotId={}, userUuid={})", plotId, userUuid, ex); - throw ex; - } finally { em.close(); } + } } @Override public void deleteByPlotId(long plotId) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); - em.createQuery("DELETE FROM PlotDeniedEntity e WHERE e.plotId = :plotId") + em.createNamedQuery("PlotDenied.deleteByPlotId") .setParameter("plotId", plotId) .executeUpdate(); tx.commit(); } catch (RuntimeException ex) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to delete all plot denied users (plotId={})", plotId, ex); - throw ex; - } finally { em.close(); } + } } } From 0d0ccb533accf80f26ff42087c16b81951851b53 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 10:00:55 +0200 Subject: [PATCH 070/141] feat: add @NotNull annotations to methods in PlotFlagRepositoryJpa for improved null safety and refactor EntityManager management --- .../repository/jpa/PlotFlagRepositoryJpa.java | 36 ++++++++----------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotFlagRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotFlagRepositoryJpa.java index 0605fe42fd..701f4556b8 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotFlagRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotFlagRepositoryJpa.java @@ -27,6 +27,7 @@ import jakarta.persistence.EntityTransaction; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; import java.util.List; import java.util.Optional; @@ -43,35 +44,29 @@ public PlotFlagRepositoryJpa(EntityManagerFactory emf) { } @Override - public List findByPlotId(long plotId) { - EntityManager em = emf.createEntityManager(); - try { + public @NotNull List findByPlotId(long plotId) { + try (EntityManager em = emf.createEntityManager()) { return em.createNamedQuery("PlotFlag.findByPlot", PlotFlagEntity.class) .setParameter("plotId", plotId) .getResultList(); - } finally { - em.close(); } } @Override - public Optional findByPlotAndName(long plotId, String flagName) { - EntityManager em = emf.createEntityManager(); - try { + public @NotNull Optional findByPlotAndName(long plotId, @NotNull String flagName) { + try (EntityManager em = emf.createEntityManager()) { return em.createNamedQuery("PlotFlag.findByPlotAndName", PlotFlagEntity.class) .setParameter("plotId", plotId) .setParameter("flag", flagName) .getResultStream().findFirst(); - } finally { - em.close(); } } @Override - public void save(PlotFlagEntity entity) { + public void save(@NotNull PlotFlagEntity entity) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); if (entity.getId() == null) { // ensure Plot reference is managed if set by id only @@ -87,18 +82,20 @@ public void save(PlotFlagEntity entity) { tx.commit(); } catch (RuntimeException e) { if (tx.isActive()) tx.rollback(); - LOGGER.error("Failed to save plot flag (plotId={}, flag={})", entity.getPlot() != null ? entity.getPlot().getId() : null, entity.getFlag(), e); - throw e; - } finally { - em.close(); + LOGGER.error( + "Failed to save plot flag (plotId={}, flag={})", + entity.getPlot() != null ? entity.getPlot().getId() : null, + entity.getFlag(), + e + ); } } @Override - public void deleteByPlotAndName(long plotId, String flagName) { + public void deleteByPlotAndName(long plotId, @NotNull String flagName) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); em.createNamedQuery("PlotFlag.deleteByPlotAndName") .setParameter("plotId", plotId) @@ -108,9 +105,6 @@ public void deleteByPlotAndName(long plotId, String flagName) { } catch (RuntimeException e) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to delete plot flag (plotId={}, flag={})", plotId, flagName, e); - throw e; - } finally { - em.close(); } } } From 2e4669bf28e41f6376d950e1c38fd86d7821dd6f Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 10:02:28 +0200 Subject: [PATCH 071/141] feat: add @NotNull annotations to methods in PlotMembershipRepositoryJpa for improved null safety and refactor EntityManager management --- .../entity/PlotMembershipEntity.java | 4 ++- .../jpa/PlotMembershipRepositoryJpa.java | 29 +++++++++---------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotMembershipEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotMembershipEntity.java index c95c151def..cfa7b3b3ea 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotMembershipEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotMembershipEntity.java @@ -31,7 +31,9 @@ @IdClass(PlotUserId.class) @NamedQueries({ @NamedQuery(name = "PlotHelper.delete", query = "DELETE FROM PlotMembershipEntity e WHERE e.plotId = :plotId AND e.userUuid = :uuid"), - @NamedQuery(name = "PlotHelper.findUsers", query = "SELECT e.userUuid FROM PlotMembershipEntity e WHERE e.plotId = :plotId") + @NamedQuery(name = "PlotHelper.findUsers", query = "SELECT e.userUuid FROM PlotMembershipEntity e WHERE e.plotId = " + + ":plotId"), + @NamedQuery(name = "PlotHelper.deleteByPlotId", query = "DELETE FROM PlotMembershipEntity e WHERE e.plotId = :plotId"), }) public class PlotMembershipEntity { @Id diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotMembershipRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotMembershipRepositoryJpa.java index c81dc861a5..9c490e5a28 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotMembershipRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotMembershipRepositoryJpa.java @@ -26,6 +26,7 @@ import jakarta.persistence.EntityTransaction; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; import java.util.List; @@ -41,20 +42,19 @@ public PlotMembershipRepositoryJpa(EntityManagerFactory emf) { } @Override - public List findUsers(long plotId) { - EntityManager em = emf.createEntityManager(); - try { + public @NotNull List findUsers(long plotId) { + try (EntityManager em = emf.createEntityManager()) { return em.createNamedQuery("PlotHelper.findUsers", String.class) .setParameter("plotId", plotId) .getResultList(); - } finally { em.close(); } + } } @Override - public void add(long plotId, String userUuid) { + public void add(long plotId, @NotNull String userUuid) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); PlotMembershipEntity e = new PlotMembershipEntity(); e.setPlotId(plotId); @@ -64,15 +64,14 @@ public void add(long plotId, String userUuid) { } catch (RuntimeException ex) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to add plot member (plotId={}, userUuid={})", plotId, userUuid, ex); - throw ex; - } finally { em.close(); } + } } @Override - public void remove(long plotId, String userUuid) { + public void remove(long plotId, @NotNull String userUuid) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); em.createNamedQuery("PlotHelper.delete") .setParameter("plotId", plotId) @@ -82,24 +81,22 @@ public void remove(long plotId, String userUuid) { } catch (RuntimeException ex) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to remove plot member (plotId={}, userUuid={})", plotId, userUuid, ex); - throw ex; - } finally { em.close(); } + } } @Override public void deleteByPlotId(long plotId) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); - em.createQuery("DELETE FROM PlotMembershipEntity e WHERE e.plotId = :plotId") + em.createNamedQuery("PlotHelper.deleteByPlotId") .setParameter("plotId", plotId) .executeUpdate(); tx.commit(); } catch (RuntimeException ex) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to delete all plot members (plotId={})", plotId, ex); - throw ex; - } finally { em.close(); } + } } } From 27bc20a65bf43e5b7da7ed861c5e2e266a941ce2 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 10:03:01 +0200 Subject: [PATCH 072/141] feat: add @NotNull annotations to methods in PlotRatingRepositoryJpa for improved null safety and refactor EntityManager management --- .../repository/jpa/PlotRatingRepositoryJpa.java | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRatingRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRatingRepositoryJpa.java index 488d5f543b..b052d9b957 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRatingRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRatingRepositoryJpa.java @@ -26,6 +26,7 @@ import jakarta.persistence.EntityTransaction; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; import java.util.List; @@ -41,22 +42,19 @@ public PlotRatingRepositoryJpa(EntityManagerFactory emf) { } @Override - public List findByPlotId(long plotId) { - EntityManager em = emf.createEntityManager(); - try { + public @NotNull List findByPlotId(long plotId) { + try (EntityManager em = emf.createEntityManager()) { return em.createNamedQuery("PlotRating.findByPlot", PlotRatingEntity.class) .setParameter("plotId", plotId) .getResultList(); - } finally { - em.close(); } } @Override - public void upsert(long plotId, String playerUuid, int rating) { + public void upsert(long plotId, @NotNull String playerUuid, int rating) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); int updated = em.createNamedQuery("PlotRating.updateValue") .setParameter("rating", rating) @@ -74,9 +72,6 @@ public void upsert(long plotId, String playerUuid, int rating) { } catch (RuntimeException e) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to upsert plot rating (plotId={}, playerUuid={}, rating={})", plotId, playerUuid, rating, e); - throw e; - } finally { - em.close(); } } } From 5b059989953d41c03fd9d2b25ed242ccd9f0576f Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 10:06:38 +0200 Subject: [PATCH 073/141] feat: refactor PlotTrustedEntity and PlotTrustedRepositoryJpa for improved query management and add @NotNull annotation for userUuid parameter --- .../persistence/entity/PlotTrustedEntity.java | 6 +++-- .../jpa/PlotTrustedRepositoryJpa.java | 27 +++++++++---------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotTrustedEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotTrustedEntity.java index b383d40edb..31dbc71973 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotTrustedEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotTrustedEntity.java @@ -30,8 +30,10 @@ @Table(name = "plot_trusted") @IdClass(PlotUserId.class) @NamedQueries({ - @NamedQuery(name = "PlotTrusted.delete", query = "DELETE FROM PlotTrustedEntity e WHERE e.plotId = :plotId AND e.userUuid = :uuid"), - @NamedQuery(name = "PlotTrusted.findUsers", query = "SELECT e.userUuid FROM PlotTrustedEntity e WHERE e.plotId = :plotId") + @NamedQuery(name = "PlotTrusted.deleteByPlotIdAndUserUUID", query = "DELETE FROM PlotTrustedEntity e WHERE e.plotId = :plotId AND e.userUuid = :uuid"), + @NamedQuery(name = "PlotTrusted.findUsers", query = "SELECT e.userUuid FROM PlotTrustedEntity e WHERE e.plotId = " + + ":plotId"), + @NamedQuery(name = "PlotTrusted.deleteByPlotId", query = "DELETE FROM PlotTrustedEntity e WHERE e.plotId = :plotId"), }) public class PlotTrustedEntity { @Id diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotTrustedRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotTrustedRepositoryJpa.java index 7ed1ef51db..9dee7b0c2f 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotTrustedRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotTrustedRepositoryJpa.java @@ -26,6 +26,7 @@ import jakarta.persistence.EntityTransaction; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; import java.util.List; @@ -42,19 +43,18 @@ public PlotTrustedRepositoryJpa(EntityManagerFactory emf) { @Override public List findUsers(long plotId) { - EntityManager em = emf.createEntityManager(); - try { + try (EntityManager em = emf.createEntityManager()) { return em.createNamedQuery("PlotTrusted.findUsers", String.class) .setParameter("plotId", plotId) .getResultList(); - } finally { em.close(); } + } } @Override - public void add(long plotId, String userUuid) { + public void add(long plotId, @NotNull String userUuid) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); PlotTrustedEntity e = new PlotTrustedEntity(); e.setPlotId(plotId); @@ -64,17 +64,16 @@ public void add(long plotId, String userUuid) { } catch (RuntimeException ex) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to add plot trusted (plotId={}, userUuid={})", plotId, userUuid, ex); - throw ex; - } finally { em.close(); } + } } @Override public void remove(long plotId, String userUuid) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); - em.createNamedQuery("PlotTrusted.delete") + em.createNamedQuery("PlotTrusted.deleteByPlotIdAndUserUUID") .setParameter("plotId", plotId) .setParameter("uuid", userUuid) .executeUpdate(); @@ -82,24 +81,22 @@ public void remove(long plotId, String userUuid) { } catch (RuntimeException ex) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to remove plot trusted (plotId={}, userUuid={})", plotId, userUuid, ex); - throw ex; - } finally { em.close(); } + } } @Override public void deleteByPlotId(long plotId) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); - em.createQuery("DELETE FROM PlotTrustedEntity e WHERE e.plotId = :plotId") + em.createNamedQuery("PlotTrusted.deleteByPlotId") .setParameter("plotId", plotId) .executeUpdate(); tx.commit(); } catch (RuntimeException ex) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to delete all plot trusted users (plotId={})", plotId, ex); - throw ex; - } finally { em.close(); } + } } } From 123d8fcc7277e014d3deed8174367a91850baca7 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 10:27:00 +0200 Subject: [PATCH 074/141] feat: add @NotNull annotations to methods in PlotSettingsRepositoryJpa for improved null safety and refactor EntityManager management --- .../jpa/PlotSettingsRepositoryJpa.java | 51 +++++++------------ 1 file changed, 17 insertions(+), 34 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotSettingsRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotSettingsRepositoryJpa.java index 8b99e8b23a..b94f6272f8 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotSettingsRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotSettingsRepositoryJpa.java @@ -26,6 +26,7 @@ import jakarta.persistence.EntityTransaction; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; import java.util.Optional; @@ -41,20 +42,17 @@ public PlotSettingsRepositoryJpa(EntityManagerFactory emf) { } @Override - public Optional findByPlotId(long plotId) { - EntityManager em = emf.createEntityManager(); - try { + public @NotNull Optional findByPlotId(long plotId) { + try (EntityManager em = emf.createEntityManager()) { return Optional.ofNullable(em.find(PlotSettingsEntity.class, plotId)); - } finally { - em.close(); } } @Override - public void save(PlotSettingsEntity settings) { + public void save(@NotNull PlotSettingsEntity settings) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); if (settings.getId() == null) { em.persist(settings); @@ -65,9 +63,6 @@ public void save(PlotSettingsEntity settings) { } catch (RuntimeException e) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to save plot settings (plotId={})", settings.getId(), e); - throw e; - } finally { - em.close(); } } @@ -75,7 +70,7 @@ public void save(PlotSettingsEntity settings) { public void deleteByPlotId(long plotId) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); PlotSettingsEntity e = em.find(PlotSettingsEntity.class, plotId); if (e != null) { @@ -85,17 +80,14 @@ public void deleteByPlotId(long plotId) { } catch (RuntimeException ex) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to delete plot settings (plotId={})", plotId, ex); - throw ex; - } finally { - em.close(); } } @Override - public void updateAlias(long plotId, String alias) { + public void updateAlias(long plotId, @NotNull String alias) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); em.createNamedQuery("PlotSettings.updateAlias") .setParameter("plotId", plotId) @@ -105,17 +97,14 @@ public void updateAlias(long plotId, String alias) { } catch (RuntimeException ex) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to update alias (plotId={})", plotId, ex); - throw ex; - } finally { - em.close(); } } @Override - public void updatePosition(long plotId, String position) { + public void updatePosition(long plotId, @NotNull String position) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); em.createNamedQuery("PlotSettings.updatePosition") .setParameter("plotId", plotId) @@ -125,9 +114,6 @@ public void updatePosition(long plotId, String position) { } catch (RuntimeException ex) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to update position (plotId={})", plotId, ex); - throw ex; - } finally { - em.close(); } } @@ -135,7 +121,7 @@ public void updatePosition(long plotId, String position) { public void updateMerged(long plotId, int mergedBitmask) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); em.createNamedQuery("PlotSettings.updateMerged") .setParameter("plotId", plotId) @@ -145,24 +131,24 @@ public void updateMerged(long plotId, int mergedBitmask) { } catch (RuntimeException ex) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to update merged (plotId={})", plotId, ex); - throw ex; - } finally { - em.close(); } } @Override - public void createDefaultIfAbsent(long plotId, String defaultPosition) { + public void createDefaultIfAbsent(long plotId, @NotNull String defaultPosition) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); PlotSettingsEntity existing = em.find(PlotSettingsEntity.class, plotId); if (existing == null) { PlotSettingsEntity se = new PlotSettingsEntity(); se.setId(plotId); // attach plot reference to satisfy FK if needed - com.plotsquared.core.persistence.entity.PlotEntity pe = em.getReference(com.plotsquared.core.persistence.entity.PlotEntity.class, plotId); + com.plotsquared.core.persistence.entity.PlotEntity pe = em.getReference( + com.plotsquared.core.persistence.entity.PlotEntity.class, + plotId + ); se.setPlot(pe); se.setPosition(defaultPosition); em.persist(se); @@ -171,9 +157,6 @@ public void createDefaultIfAbsent(long plotId, String defaultPosition) { } catch (RuntimeException ex) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to create default settings if absent (plotId={})", plotId, ex); - throw ex; - } finally { - em.close(); } } } From 425966321047265cd1f81b09851d9e64fae6e747 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 11:58:55 +0200 Subject: [PATCH 075/141] feat: add named queries for retrieving and deleting plots in various entities for improved data management --- .../persistence/entity/PlotDeniedEntity.java | 4 +- .../core/persistence/entity/PlotEntity.java | 6 + .../persistence/entity/PlotFlagEntity.java | 6 +- .../entity/PlotMembershipEntity.java | 3 + .../persistence/entity/PlotRatingEntity.java | 6 +- .../entity/PlotSettingsEntity.java | 14 +- .../persistence/entity/PlotTrustedEntity.java | 2 + .../repository/jpa/PlotRepositoryJpa.java | 468 +++++++----------- 8 files changed, 215 insertions(+), 294 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotDeniedEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotDeniedEntity.java index f3589a81ee..bba252957a 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotDeniedEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotDeniedEntity.java @@ -33,7 +33,9 @@ @NamedQuery(name = "PlotDenied.delete", query = "DELETE FROM PlotDeniedEntity e WHERE e.plotId = :plotId AND e.userUuid = :uuid"), @NamedQuery(name = "PlotDenied.findUsers", query = "SELECT e.userUuid FROM PlotDeniedEntity e WHERE e.plotId = :plotId"), @NamedQuery(name = "PlotDenied.deleteAll", query = "DELETE FROM PlotDeniedEntity e WHERE e.plotId = :plotId"), - @NamedQuery(name = "PlotDenied.deleteByPlotId", query = "DELETE FROM PlotDeniedEntity e WHERE e.plotId = :plotId") + @NamedQuery(name = "PlotDenied.deleteByPlotId", query = "DELETE FROM PlotDeniedEntity e WHERE e.plotId = :plotId"), + @NamedQuery(name = "PlotDenied.findAll", query = "SELECT e FROM PlotDeniedEntity e"), + @NamedQuery(name = "PlotDenied.deleteAllInPlotIds", query = "DELETE FROM PlotDeniedEntity e WHERE e.plotId IN :plotIds") }) public class PlotDeniedEntity { @Id diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotEntity.java index ece8c2bfc4..e6d17e93bc 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotEntity.java @@ -33,6 +33,7 @@ @Entity @Table(name = "plot") @NamedQueries({ + @NamedQuery(name = "Plot.findAll", query = "SELECT p FROM PlotEntity p"), @NamedQuery(name = "Plot.findByWorldAndId", query = "SELECT p FROM PlotEntity p WHERE p.world = :world AND p.plotIdX = :x AND p.plotIdZ = :z"), @NamedQuery(name = "Plot.findByOwner", query = "SELECT p FROM PlotEntity p WHERE p.owner = :owner"), @NamedQuery(name = "Plot.findByWorld", query = "SELECT p FROM PlotEntity p WHERE p.world = :world"), @@ -47,6 +48,11 @@ query = "UPDATE PlotEntity p SET p.plotIdX = :plotIdX, p.plotIdZ = :plotIdZ, p.world = :world WHERE p.id = :id" ), @NamedQuery(name = "Plot.setOwner", query = "UPDATE PlotEntity p SET p.owner = :owner WHERE p.world = :world AND p.plotIdX = :x AND p.plotIdZ = :z"), + @NamedQuery(name = "Plot.replaceWorldInBounds", query = "UPDATE PlotEntity p SET p.world = :newWorld WHERE p.world = " + + ":oldWorld AND p.plotIdX BETWEEN :minX AND :maxX AND p.plotIdZ BETWEEN :minZ AND :maxZ"), + @NamedQuery(name = "Plot.replaceWorldAll", query = "UPDATE PlotEntity p SET p.world = :newWorld WHERE p.world = " + + ":oldWorld"), + @NamedQuery(name = "Plot.deleteAllInIds", query = "DELETE FROM PlotEntity p WHERE p.id IN :ids"), }) public class PlotEntity { @Id diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotFlagEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotFlagEntity.java index b42ab3fdf7..dec5b9f5ed 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotFlagEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotFlagEntity.java @@ -36,7 +36,11 @@ @NamedQueries({ @NamedQuery(name = "PlotFlag.findByPlot", query = "SELECT f FROM PlotFlagEntity f WHERE f.plot.id = :plotId"), @NamedQuery(name = "PlotFlag.findByPlotAndName", query = "SELECT f FROM PlotFlagEntity f WHERE f.plot.id = :plotId AND f.flag = :flag"), - @NamedQuery(name = "PlotFlag.deleteByPlotAndName", query = "DELETE FROM PlotFlagEntity f WHERE f.plot.id = :plotId AND f.flag = :flag") + @NamedQuery(name = "PlotFlag.deleteByPlotAndName", query = "DELETE FROM PlotFlagEntity f WHERE f.plot.id = :plotId AND " + + "f.flag = :flag"), + @NamedQuery(name = "PlotFlag.deleteByPlot", query = "DELETE FROM PlotFlagEntity f WHERE f.plot.id = :plotId"), + @NamedQuery(name = "PlotFlag.findAll", query = "SELECT f FROM PlotFlagEntity f"), + @NamedQuery(name = "PlotFlag.deleteAllInPlotIds", query = "DELETE FROM PlotFlagEntity f WHERE f.plot.id IN :plotIds") }) public class PlotFlagEntity { @Id diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotMembershipEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotMembershipEntity.java index cfa7b3b3ea..30157c76ab 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotMembershipEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotMembershipEntity.java @@ -25,6 +25,7 @@ import jakarta.persistence.NamedQueries; import jakarta.persistence.NamedQuery; import jakarta.persistence.Table; +import jdk.jfr.Name; @Entity @Table(name = "plot_helpers") @@ -34,6 +35,8 @@ @NamedQuery(name = "PlotHelper.findUsers", query = "SELECT e.userUuid FROM PlotMembershipEntity e WHERE e.plotId = " + ":plotId"), @NamedQuery(name = "PlotHelper.deleteByPlotId", query = "DELETE FROM PlotMembershipEntity e WHERE e.plotId = :plotId"), + @NamedQuery(name = "PlotHelper.findAll", query = "SELECT e FROM PlotMembershipEntity e"), + @NamedQuery(name = "PlotHelper.deleteAllInPlotIds", query = "DELETE FROM PlotMembershipEntity e WHERE e.plotId IN :plotIds") }) public class PlotMembershipEntity { @Id diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotRatingEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotRatingEntity.java index 65b2f8fe9f..7dca44c2aa 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotRatingEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotRatingEntity.java @@ -32,7 +32,11 @@ @NamedQueries({ @NamedQuery(name = "PlotRating.findByPlot", query = "SELECT r FROM PlotRatingEntity r WHERE r.plotId = :plotId"), @NamedQuery(name = "PlotRating.upsert", query = "UPDATE PlotRatingEntity r SET r.rating = :rating WHERE r.plotId = :plotId AND r.player = :player"), - @NamedQuery(name = "PlotRating.updateValue", query = "UPDATE PlotRatingEntity r SET r.rating = :rating WHERE r.plotId = :plotId AND r.player = :player") + @NamedQuery(name = "PlotRating.updateValue", query = "UPDATE PlotRatingEntity r SET r.rating = :rating WHERE r.plotId =" + + " :plotId AND r.player = :player"), + @NamedQuery(name = "PlotRating.deleteByPlot", query = "DELETE FROM PlotRatingEntity r WHERE r.plotId = :plotId"), + @NamedQuery(name = "PlotRating.findAll", query = "SELECT r FROM PlotRatingEntity r"), + @NamedQuery(name = "PlotRating.deleteAllInPlotIds", query = "DELETE FROM PlotRatingEntity r WHERE r.plotId IN :plotIds") }) public class PlotRatingEntity { @Id @Column(name = "plot_plot_id") diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotSettingsEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotSettingsEntity.java index a6cc397eb5..e109f2478e 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotSettingsEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotSettingsEntity.java @@ -23,15 +23,21 @@ import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.MapsId; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; import jakarta.persistence.OneToOne; import jakarta.persistence.Table; @Entity @Table(name = "plot_settings") -@jakarta.persistence.NamedQueries({ - @jakarta.persistence.NamedQuery(name = "PlotSettings.updateAlias", query = "UPDATE PlotSettingsEntity s SET s.alias = :alias WHERE s.id = :plotId"), - @jakarta.persistence.NamedQuery(name = "PlotSettings.updatePosition", query = "UPDATE PlotSettingsEntity s SET s.position = :pos WHERE s.id = :plotId"), - @jakarta.persistence.NamedQuery(name = "PlotSettings.updateMerged", query = "UPDATE PlotSettingsEntity s SET s.merged = :merged WHERE s.id = :plotId") +@NamedQueries({ + @NamedQuery(name = "PlotSettings.updateAlias", query = "UPDATE PlotSettingsEntity s SET s.alias = :alias WHERE s.id = :plotId"), + @NamedQuery(name = "PlotSettings.updatePosition", query = "UPDATE PlotSettingsEntity s SET s.position = :pos WHERE s.id = :plotId"), + @NamedQuery(name = "PlotSettings.updateMerged", query = "UPDATE PlotSettingsEntity s SET s.merged =" + + " :merged WHERE s.id = :plotId"), + @NamedQuery(name = "PlotSettings.deleteByPlot", query = "DELETE FROM PlotSettingsEntity s WHERE s.id = :plotId"), + @NamedQuery(name = "PlotSettings.findAll", query = "SELECT s FROM PlotSettingsEntity s"), + @NamedQuery(name = "PlotSettings.deleteAllInPlotIds", query = "DELETE FROM PlotSettingsEntity s WHERE s.id IN :plotIds") }) public class PlotSettingsEntity { @Id diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotTrustedEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotTrustedEntity.java index 31dbc71973..0320b9348e 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotTrustedEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotTrustedEntity.java @@ -34,6 +34,8 @@ @NamedQuery(name = "PlotTrusted.findUsers", query = "SELECT e.userUuid FROM PlotTrustedEntity e WHERE e.plotId = " + ":plotId"), @NamedQuery(name = "PlotTrusted.deleteByPlotId", query = "DELETE FROM PlotTrustedEntity e WHERE e.plotId = :plotId"), + @NamedQuery(name = "PlotTrusted.findAll", query = "SELECT e FROM PlotTrustedEntity e"), + @NamedQuery(name = "PlotTrusted.deleteAllInPlotIds", query = "DELETE FROM PlotTrustedEntity e WHERE e.plotId IN :plotIds") }) public class PlotTrustedEntity { @Id diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java index 8a2cd111c3..06a8fcaedd 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java @@ -19,22 +19,42 @@ package com.plotsquared.core.persistence.repository.jpa; import com.google.inject.Inject; +import com.plotsquared.core.configuration.Settings; +import com.plotsquared.core.location.BlockLoc; +import com.plotsquared.core.persistence.entity.PlotDeniedEntity; import com.plotsquared.core.persistence.entity.PlotEntity; +import com.plotsquared.core.persistence.entity.PlotFlagEntity; +import com.plotsquared.core.persistence.entity.PlotMembershipEntity; +import com.plotsquared.core.persistence.entity.PlotRatingEntity; +import com.plotsquared.core.persistence.entity.PlotSettingsEntity; +import com.plotsquared.core.persistence.entity.PlotTrustedEntity; import com.plotsquared.core.persistence.repository.api.PlotRepository; import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.PlotId; +import com.plotsquared.core.plot.flag.FlagParseException; +import com.plotsquared.core.plot.flag.types.BlockTypeListFlag; +import com.plotsquared.core.util.HashUtil; import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManagerFactory; import jakarta.persistence.EntityTransaction; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.UUID; public class PlotRepositoryJpa implements PlotRepository { private static final Logger LOGGER = LogManager.getLogger(PlotRepositoryJpa.class); + private static final UUID EVERYONE = UUID.fromString("1-1-3-3-7"); private final EntityManagerFactory emf; @@ -47,16 +67,9 @@ public PlotRepositoryJpa(EntityManagerFactory emf) { public boolean createPlotSafe(final Plot plot) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); - String world = null; - try { - world = plot.getWorldName(); - } catch (Throwable ignored) { - } - if (world == null) { - world = plot.getArea().toString(); - } + String world = Optional.of(plot).map(Plot::getWorldName).orElse(Optional.of(plot).map(Plot::getArea).map(Object::toString).orElse(null)); Optional existing = findByWorldAndId(world, plot.getId().getX(), plot.getId().getY()); if (existing.isPresent()) { tx.commit(); @@ -65,19 +78,12 @@ public boolean createPlotSafe(final Plot plot) { PlotEntity pe = new PlotEntity(); pe.setPlotIdX(plot.getId().getX()); pe.setPlotIdZ(plot.getId().getY()); - UUID ownerUuid = null; - try { - ownerUuid = plot.getOwnerAbs(); - } catch (Throwable ignored) { - } - pe.setOwner(ownerUuid != null ? ownerUuid.toString() : com.plotsquared.core.database.DBFunc.EVERYONE.toString()); + UUID ownerUuid = plot.getOwnerAbs(); + pe.setOwner(Optional.ofNullable(ownerUuid).map(UUID::toString).orElse(EVERYONE.toString())); pe.setWorld(world); em.persist(pe); em.flush(); - if (pe.getId() != null) { - plot.temp = pe.getId().intValue(); - } - com.plotsquared.core.persistence.entity.PlotSettingsEntity se = new com.plotsquared.core.persistence.entity.PlotSettingsEntity(); + PlotSettingsEntity se = new PlotSettingsEntity(); se.setPlot(pe); se.setPosition("DEFAULT"); em.persist(se); @@ -88,42 +94,26 @@ public boolean createPlotSafe(final Plot plot) { tx.rollback(); } LOGGER.error("Failed to create plot safely (plot={})", plot, e); - throw e; - } finally { - em.close(); } + return false; } @Override public void createPlotAndSettings(final Plot plot) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); - String world = null; - try { - world = plot.getWorldName(); - } catch (Throwable ignored) { - } - if (world == null) { - world = plot.getArea().toString(); - } + String world = Optional.of(plot).map(Plot::getWorldName).orElse(Optional.of(plot).map(Plot::getArea).map(Object::toString).orElse(null)); PlotEntity pe = new PlotEntity(); pe.setPlotIdX(plot.getId().getX()); pe.setPlotIdZ(plot.getId().getY()); - UUID ownerUuid = null; - try { - ownerUuid = plot.getOwnerAbs(); - } catch (Throwable ignored) { - } - pe.setOwner(ownerUuid != null ? ownerUuid.toString() : com.plotsquared.core.database.DBFunc.EVERYONE.toString()); + UUID ownerUuid = plot.getOwnerAbs(); + pe.setOwner(Optional.ofNullable(ownerUuid).map(UUID::toString).orElse(EVERYONE.toString())); pe.setWorld(world); em.persist(pe); em.flush(); - if (pe.getId() != null) { - plot.temp = pe.getId().intValue(); - } - com.plotsquared.core.persistence.entity.PlotSettingsEntity se = new com.plotsquared.core.persistence.entity.PlotSettingsEntity(); + PlotSettingsEntity se = new PlotSettingsEntity(); se.setPlot(pe); se.setPosition("DEFAULT"); em.persist(se); @@ -134,40 +124,27 @@ public void createPlotAndSettings(final Plot plot) { } LOGGER.error("Failed to create plot and settings (plot={})", plot, e); throw e; - } finally { - em.close(); } } @Override public void createPlotsAndData(final List plots) { - if (plots == null || plots.isEmpty()) { + if (plots.isEmpty()) { return; } EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); for (final Plot plot : plots) { // Persist plot row PlotEntity pe = new PlotEntity(); pe.setPlotIdX(plot.getId().getX()); pe.setPlotIdZ(plot.getId().getY()); - java.util.UUID ownerUuid = null; - try { - ownerUuid = plot.getOwnerAbs(); - } catch (Throwable ignored) { - } - pe.setOwner(ownerUuid != null ? ownerUuid.toString() : com.plotsquared.core.database.DBFunc.EVERYONE.toString()); + UUID ownerUuid = plot.getOwnerAbs(); + pe.setOwner(Optional.ofNullable(ownerUuid).map(UUID::toString).orElse(EVERYONE.toString())); // Prefer world name for consistency with other queries - String world = null; - try { - world = plot.getWorldName(); - } catch (Throwable ignored) { - } - if (world == null) { - world = plot.getArea().toString(); - } + String world = Optional.of(plot).map(Plot::getWorldName).orElse(Optional.of(plot).map(Plot::getArea).map(Object::toString).orElse(null)); pe.setWorld(world); em.persist(pe); em.flush(); // ensure ID is generated @@ -177,30 +154,28 @@ public void createPlotsAndData(final List plots) { // Persist settings (alias, merged, position) similar to legacy behavior try { var ps = plot.getSettings(); - if (ps != null) { - com.plotsquared.core.persistence.entity.PlotSettingsEntity se = new com.plotsquared.core.persistence.entity.PlotSettingsEntity(); - se.setPlot(pe); - String alias = ps.getAlias(); - if (alias != null && !alias.isEmpty()) { - se.setAlias(alias); - } - boolean[] merged = ps.getMerged(); - if (merged != null) { - int hash = com.plotsquared.core.util.HashUtil.hash(merged); - se.setMerged(hash); - } - var loc = ps.getPosition(); - String position = "DEFAULT"; - if (loc != null) { - if (loc.getY() == 0) { - position = "DEFAULT"; - } else { - position = loc.getX() + "," + loc.getY() + "," + loc.getZ(); - } + PlotSettingsEntity se = new PlotSettingsEntity(); + se.setPlot(pe); + String alias = ps.getAlias(); + if (alias != null && !alias.isEmpty()) { + se.setAlias(alias); + } + boolean[] merged = ps.getMerged(); + if (merged != null) { + int hash = HashUtil.hash(merged); + se.setMerged(hash); + } + var loc = ps.getPosition(); + String position = "DEFAULT"; + if (loc != null) { + if (loc.getY() == 0) { + position = "DEFAULT"; + } else { + position = loc.getX() + "," + loc.getY() + "," + loc.getZ(); } - se.setPosition(position); - em.persist(se); } + se.setPosition(position); + em.persist(se); } catch (Throwable t) { // log and continue LOGGER.warn( @@ -215,9 +190,9 @@ public void createPlotsAndData(final List plots) { // Persist flags try { var flagContainer = plot.getFlagContainer(); - if (flagContainer != null && flagContainer.getFlagMap() != null) { + if (flagContainer.getFlagMap() != null) { for (var flagEntry : flagContainer.getFlagMap().values()) { - com.plotsquared.core.persistence.entity.PlotFlagEntity fe = new com.plotsquared.core.persistence.entity.PlotFlagEntity(); + PlotFlagEntity fe = new PlotFlagEntity(); fe.setPlot(pe); fe.setFlag(flagEntry.getName()); fe.setValue(flagEntry.toString()); @@ -237,33 +212,33 @@ public void createPlotsAndData(final List plots) { // Persist tiers: NOTE legacy mapping members->trusted, trusted->helpers try { // helpers table from plot.getTrusted() - for (java.util.UUID uuid : plot.getTrusted()) { - com.plotsquared.core.persistence.entity.PlotMembershipEntity e = new com.plotsquared.core.persistence.entity.PlotMembershipEntity(); + for (UUID uuid : plot.getTrusted()) { + PlotMembershipEntity e = new PlotMembershipEntity(); e.setPlotId(plotId); e.setUserUuid(uuid.toString()); em.persist(e); } // trusted table from plot.getMembers() - for (java.util.UUID uuid : plot.getMembers()) { - com.plotsquared.core.persistence.entity.PlotTrustedEntity e = new com.plotsquared.core.persistence.entity.PlotTrustedEntity(); + for (UUID uuid : plot.getMembers()) { + PlotTrustedEntity e = new PlotTrustedEntity(); e.setPlotId(plotId); e.setUserUuid(uuid.toString()); em.persist(e); } // denied table from plot.getDenied() - for (java.util.UUID uuid : plot.getDenied()) { - com.plotsquared.core.persistence.entity.PlotDeniedEntity e = new com.plotsquared.core.persistence.entity.PlotDeniedEntity(); + for (UUID uuid : plot.getDenied()) { + PlotDeniedEntity e = new PlotDeniedEntity(); e.setPlotId(plotId); e.setUserUuid(uuid.toString()); em.persist(e); } - } catch (Throwable t) { + } catch (Exception exception) { LOGGER.warn( "Failed to persist tiers for plot (x={}, z={}, world={})", plot.getId().getX(), plot.getId().getY(), world, - t + exception ); } } @@ -273,14 +248,11 @@ public void createPlotsAndData(final List plots) { tx.rollback(); } LOGGER.error("Failed bulk create plots and data", e); - throw e; - } finally { - em.close(); } } @Override - public boolean swapPlots(final Plot plot1, final Plot plot2) { + public boolean swapPlots(final @NotNull Plot plot1, final @NotNull Plot plot2) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); try { @@ -310,12 +282,12 @@ public boolean swapPlots(final Plot plot1, final Plot plot2) { } @Override - public void replaceWorldInRange(String oldWorld, String newWorld, int minX, int minZ, int maxX, int maxZ) { + public void replaceWorldInRange(@NotNull String oldWorld, @NotNull String newWorld, int minX, int minZ, int maxX, int maxZ) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); - em.createQuery("UPDATE PlotEntity p SET p.world = :newWorld WHERE p.world = :oldWorld AND p.plotIdX BETWEEN :minX AND :maxX AND p.plotIdZ BETWEEN :minZ AND :maxZ") + em.createNamedQuery("Plot.replaceWorldInBounds") .setParameter("newWorld", newWorld) .setParameter("oldWorld", oldWorld) .setParameter("minX", minX) @@ -326,20 +298,26 @@ public void replaceWorldInRange(String oldWorld, String newWorld, int minX, int tx.commit(); } catch (RuntimeException e) { if (tx.isActive()) tx.rollback(); - LOGGER.error("Failed to replace world in range (oldWorld={}, newWorld={}, range=[{}..{}]x[{}..{}])", oldWorld, newWorld, minX, maxX, minZ, maxZ, e); - throw e; - } finally { - em.close(); + LOGGER.error( + "Failed to replace world in range (oldWorld={}, newWorld={}, range=[{}..{}]x[{}..{}])", + oldWorld, + newWorld, + minX, + maxX, + minZ, + maxZ, + e + ); } } @Override - public void replaceWorldAll(String oldWorld, String newWorld) { + public void replaceWorldAll(@NotNull String oldWorld, @NotNull String newWorld) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); - em.createQuery("UPDATE PlotEntity p SET p.world = :newWorld WHERE p.world = :oldWorld") + em.createNamedQuery("Plot.replaceWorldAll") .setParameter("newWorld", newWorld) .setParameter("oldWorld", oldWorld) .executeUpdate(); @@ -347,14 +325,11 @@ public void replaceWorldAll(String oldWorld, String newWorld) { } catch (RuntimeException e) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to replace world (all plots) oldWorld={}, newWorld={}", oldWorld, newWorld, e); - throw e; - } finally { - em.close(); } } @Override - public void movePlots(final Plot originPlot, final Plot newPlot) { + public void movePlots(final @NotNull Plot originPlot, final @NotNull Plot newPlot) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); try (em) { @@ -375,12 +350,11 @@ public void movePlots(final Plot originPlot, final Plot newPlot) { tx.rollback(); } LOGGER.error("Failed to move plots (plot1={}, plot2={})", originPlot, newPlot, e); - throw e; } } @Override - public void setOwner(final Plot plot, final UUID newOwner) { + public void setOwner(final @NotNull Plot plot, final @NotNull UUID newOwner) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); try (em) { @@ -396,77 +370,61 @@ public void setOwner(final Plot plot, final UUID newOwner) { tx.rollback(); } LOGGER.error("Failed to set plot owner (plot={}, newOwner={})", plot, newOwner, e); - throw e; } } @Override - public Optional findById(long id) { - EntityManager em = emf.createEntityManager(); - try { + public @NotNull Optional findById(long id) { + try (EntityManager em = emf.createEntityManager()) { return Optional.ofNullable(em.find(PlotEntity.class, id)); - } finally { - em.close(); } } @Override - public Optional findByXAndZAnyWorld(final int x, final int z, final String world) { - EntityManager em = emf.createEntityManager(); - try { + public @NotNull Optional findByXAndZAnyWorld(final int x, final int z, final @NotNull String world) { + try (EntityManager em = emf.createEntityManager()) { return em.createNamedQuery("Plot.findByXAndZAndWorld", PlotEntity.class) .setParameter("x", x) .setParameter("z", z) .setParameter("world", world) .getResultStream().findFirst(); - } finally { - em.close(); } } @Override - public Optional findByWorldAndId(String world, int x, int z) { - EntityManager em = emf.createEntityManager(); - try { + public @NotNull Optional findByWorldAndId(@NotNull String world, int x, int z) { + try (EntityManager em = emf.createEntityManager()) { return em.createNamedQuery("Plot.findByWorldAndId", PlotEntity.class) .setParameter("world", world) .setParameter("x", x) .setParameter("z", z) .getResultStream().findFirst(); - } finally { - em.close(); } } @Override - public List findByOwner(String ownerUuid) { - EntityManager em = emf.createEntityManager(); - try { + public @NotNull List findByOwner(@NotNull String ownerUuid) { + try (EntityManager em = emf.createEntityManager()) { return em.createNamedQuery("Plot.findByOwner", PlotEntity.class) .setParameter("owner", ownerUuid) .getResultList(); - } finally { - em.close(); } } @Override - public List findByWorld(String world) { - EntityManager em = emf.createEntityManager(); - try { + public @NotNull List findByWorld(@NotNull String world) { + try (EntityManager em = emf.createEntityManager()) { return em.createNamedQuery("Plot.findByWorld", PlotEntity.class) .setParameter("world", world) .getResultList(); - } finally { - em.close(); } } @Override - public void save(PlotEntity plot) { + public void save(@NotNull PlotEntity plot) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); if (plot.getId() == null) { em.persist(plot); @@ -486,9 +444,6 @@ public void save(PlotEntity plot) { plot.getPlotIdZ(), e ); - throw e; - } finally { - em.close(); } } @@ -496,7 +451,7 @@ public void save(PlotEntity plot) { public void deleteById(long id) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); PlotEntity ref = em.find(PlotEntity.class, id); if (ref != null) { @@ -508,9 +463,6 @@ public void deleteById(long id) { tx.rollback(); } LOGGER.error("Failed to delete plot by id (id={})", id, e); - throw e; - } finally { - em.close(); } } @@ -554,16 +506,13 @@ public void deleteRatings(final Plot plot) { public void delete(final Plot plot) { EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); - String world = null; - try { - world = plot.getWorldName(); - } catch (Throwable ignored) { - } - if (world == null) { - world = plot.getArea().toString(); - } + String world = Optional.of(plot).map(Plot::getWorldName).orElse(Optional + .of(plot) + .map(Plot::getArea) + .map(Object::toString) + .orElse(null)); PlotEntity pe = em.createNamedQuery("Plot.findByWorldAndId", PlotEntity.class) .setParameter("world", world) .setParameter("x", plot.getId().getX()) @@ -572,23 +521,23 @@ public void delete(final Plot plot) { if (pe != null && pe.getId() != null) { Long plotId = pe.getId(); // Delete children first to satisfy FK constraints - em.createQuery("DELETE FROM PlotFlagEntity f WHERE f.plot.id = :plotId") + em.createNamedQuery("PlotFlag.deleteByPlot") .setParameter("plotId", plotId) .executeUpdate(); - em.createQuery("DELETE FROM PlotMembershipEntity e WHERE e.plotId = :plotId") + em.createNamedQuery("PlotHelper.deleteByPlotId") .setParameter("plotId", plotId) .executeUpdate(); - em.createQuery("DELETE FROM PlotTrustedEntity e WHERE e.plotId = :plotId") + em.createNamedQuery("PlotTrusted.deleteByPlotId") .setParameter("plotId", plotId) .executeUpdate(); - em.createQuery("DELETE FROM PlotDeniedEntity e WHERE e.plotId = :plotId") + em.createNamedQuery("PlotDenied.deleteByPlotId") .setParameter("plotId", plotId) .executeUpdate(); - em.createQuery("DELETE FROM PlotRatingEntity r WHERE r.plotId = :plotId") + em.createNamedQuery("PlotRating.deleteByPlot") .setParameter("plotId", plotId) .executeUpdate(); // Remove settings explicitly to mirror legacy behavior and avoid orphan rows - em.createQuery("DELETE FROM PlotSettingsEntity s WHERE s.id = :plotId") + em.createNamedQuery("PlotSettings.deleteByPlot") .setParameter("plotId", plotId) .executeUpdate(); // Remove plot @@ -601,44 +550,39 @@ public void delete(final Plot plot) { tx.rollback(); } LOGGER.error("Failed to delete plot (plot={})", plot, e); - throw e; - } finally { - em.close(); } } @Override - public java.util.HashMap> getPlots() { - EntityManager em = emf.createEntityManager(); - try { - java.util.HashMap> worldMap = new java.util.HashMap<>(); - java.util.Map byId = new java.util.HashMap<>(); - java.util.Map uuidCache = new java.util.HashMap<>(); - + public HashMap> getPlots() { + HashMap> worldMap = new HashMap<>(); + Map byId = new HashMap<>(); + Map uuidCache = new HashMap<>(); + try (EntityManager em = emf.createEntityManager()) { // Load plots - List plots = em.createQuery("SELECT p FROM PlotEntity p", PlotEntity.class).getResultList(); + List plots = em.createNamedQuery("Plot.findAll", PlotEntity.class).getResultList(); for (PlotEntity p : plots) { String ownerStr = p.getOwner(); - java.util.UUID owner; + UUID owner; if (ownerStr == null) { - owner = com.plotsquared.core.database.DBFunc.EVERYONE; + owner = EVERYONE; } else { owner = uuidCache.get(ownerStr); if (owner == null) { try { - owner = java.util.UUID.fromString(ownerStr); + owner = UUID.fromString(ownerStr); } catch (IllegalArgumentException ex) { - String base = com.plotsquared.core.configuration.Settings.UUID.FORCE_LOWERCASE + String base = Settings.UUID.FORCE_LOWERCASE ? ("OfflinePlayer:" + ownerStr.toLowerCase()) : ("OfflinePlayer:" + ownerStr); - owner = java.util.UUID.nameUUIDFromBytes(base.getBytes(java.nio.charset.StandardCharsets.UTF_8)); + owner = UUID.nameUUIDFromBytes(base.getBytes(StandardCharsets.UTF_8)); } uuidCache.put(ownerStr, owner); } } long time = p.getTimestamp() != null ? p.getTimestamp().getTime() : System.currentTimeMillis(); - com.plotsquared.core.plot.PlotId pid = com.plotsquared.core.plot.PlotId.of(p.getPlotIdX(), p.getPlotIdZ()); - com.plotsquared.core.plot.Plot plot = new com.plotsquared.core.plot.Plot( + PlotId pid = PlotId.of(p.getPlotIdX(), p.getPlotIdZ()); + Plot plot = new Plot( pid, owner, new java.util.HashSet<>(), @@ -652,83 +596,53 @@ public java.util.HashMap new java.util.HashMap<>()).put(pid, plot); + worldMap.computeIfAbsent(p.getWorld(), k -> new HashMap<>()).put(pid, plot); if (p.getId() != null) { byId.put(p.getId(), plot); } } // Ratings (optional) - if (com.plotsquared.core.configuration.Settings.Enabled_Components.RATING_CACHE) { - var ratings = em.createQuery( - "SELECT r FROM PlotRatingEntity r", - com.plotsquared.core.persistence.entity.PlotRatingEntity.class - ).getResultList(); + if (Settings.Enabled_Components.RATING_CACHE) { + var ratings = em.createNamedQuery("PlotRating.findAll", PlotRatingEntity.class).getResultList(); for (var r : ratings) { var plot = byId.get(r.getPlotId()); if (plot != null) { - try { - plot.getSettings().getRatings().put(java.util.UUID.fromString(r.getPlayer()), r.getRating()); - } catch (IllegalArgumentException ignored) { - } + plot.getSettings().getRatings().put(UUID.fromString(r.getPlayer()), r.getRating()); } } } // Helpers -> trusted - var helpers = em.createQuery( - "SELECT e FROM PlotMembershipEntity e", - com.plotsquared.core.persistence.entity.PlotMembershipEntity.class - ).getResultList(); + var helpers = em.createNamedQuery("PlotHelper.findAll", PlotMembershipEntity.class).getResultList(); for (var e : helpers) { var plot = byId.get(e.getPlotId()); if (plot != null) { - try { - plot.getTrusted().add(java.util.UUID.fromString(e.getUserUuid())); - } catch (IllegalArgumentException ignored) { - } + plot.getTrusted().add(UUID.fromString(e.getUserUuid())); } } // Trusted -> members - var trusted = em.createQuery( - "SELECT e FROM PlotTrustedEntity e", - com.plotsquared.core.persistence.entity.PlotTrustedEntity.class - ).getResultList(); + var trusted = em.createNamedQuery("PlotTrusted.findAll", PlotTrustedEntity.class).getResultList(); for (var e : trusted) { var plot = byId.get(e.getPlotId()); if (plot != null) { - try { - plot.getMembers().add(java.util.UUID.fromString(e.getUserUuid())); - } catch (IllegalArgumentException ignored) { - } + plot.getMembers().add(UUID.fromString(e.getUserUuid())); } } // Denied - var denied = em.createQuery( - "SELECT e FROM PlotDeniedEntity e", - com.plotsquared.core.persistence.entity.PlotDeniedEntity.class - ).getResultList(); + var denied = em.createNamedQuery("PlotDenied.findAll", PlotDeniedEntity.class).getResultList(); for (var e : denied) { var plot = byId.get(e.getPlotId()); if (plot != null) { - try { - plot.getDenied().add(java.util.UUID.fromString(e.getUserUuid())); - } catch (IllegalArgumentException ignored) { - } + plot.getDenied().add(UUID.fromString(e.getUserUuid())); } } // Flags - try { - com.plotsquared.core.plot.flag.types.BlockTypeListFlag.skipCategoryVerification = true; - } catch (Throwable ignored) { - } - var flags = em.createQuery( - "SELECT f FROM PlotFlagEntity f", - com.plotsquared.core.persistence.entity.PlotFlagEntity.class - ).getResultList(); + BlockTypeListFlag.skipCategoryVerification = true; + var flags = em.createNamedQuery("PlotFlag.findAll", PlotFlagEntity.class).getResultList(); for (var f : flags) { var plot = byId.get(f.getPlot().getId()); if (plot != null) { @@ -739,24 +653,14 @@ public java.util.HashMap ids) { - if (ids == null || ids.isEmpty()) return; + public void purgeIds(@NotNull Set ids) { + if (ids.isEmpty()) return; EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); // Convert Integer to Long (plot ids are Long) - java.util.Set longIds = new java.util.HashSet<>(); + Set longIds = new HashSet<>(); for (Integer i : ids) { if (i != null) longIds.add(i.longValue()); } @@ -808,53 +710,50 @@ public void purgeIds(java.util.Set ids) { return; } // Delete child tables first - em.createQuery("DELETE FROM PlotFlagEntity f WHERE f.plot.id IN :ids") - .setParameter("ids", longIds) + em.createNamedQuery("PlotFlag.deleteAllInPlotIds") + .setParameter("plotIds", longIds) .executeUpdate(); - em.createQuery("DELETE FROM PlotMembershipEntity e WHERE e.plotId IN :ids") - .setParameter("ids", longIds) + em.createNamedQuery("PlotTrusted.deleteAllInPlotIds") + .setParameter("plotIds", longIds) .executeUpdate(); - em.createQuery("DELETE FROM PlotTrustedEntity e WHERE e.plotId IN :ids") - .setParameter("ids", longIds) + em.createNamedQuery("PlotHelper.deleteAllInPlotIds") + .setParameter("plotIds", longIds) .executeUpdate(); - em.createQuery("DELETE FROM PlotDeniedEntity e WHERE e.plotId IN :ids") - .setParameter("ids", longIds) + em.createNamedQuery("PlotDenied.deleteAllInPlotIds") + .setParameter("plotIds", longIds) .executeUpdate(); - em.createQuery("DELETE FROM PlotRatingEntity r WHERE r.plotId IN :ids") - .setParameter("ids", longIds) + em.createNamedQuery("PlotRating.deleteAllInPlotIds") + .setParameter("plotIds", longIds) .executeUpdate(); - em.createQuery("DELETE FROM PlotSettingsEntity s WHERE s.id IN :ids") - .setParameter("ids", longIds) + em.createNamedQuery("PlotSettings.deleteAllInPlotIds") + .setParameter("plotIds", longIds) .executeUpdate(); // Finally delete plots - em.createQuery("DELETE FROM PlotEntity p WHERE p.id IN :ids") + em.createNamedQuery("Plot.deleteAllInIds") .setParameter("ids", longIds) .executeUpdate(); tx.commit(); } catch (RuntimeException e) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to purge plots by ids (ids={})", ids, e); - throw e; - } finally { - em.close(); } } @Override - public void purgeByWorldAndPlotIds(String world, java.util.Set plotIds) { - if (world == null || world.isEmpty() || plotIds == null || plotIds.isEmpty()) return; + public void purgeByWorldAndPlotIds(String world, Set plotIds) { + if (world.isEmpty() || plotIds.isEmpty()) return; EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); - try { + try (em) { tx.begin(); // Resolve plot ids by fetching candidates in the world and filtering in-memory - List ids = new java.util.ArrayList<>(); + List ids = new ArrayList<>(); List candidates = em.createNamedQuery("Plot.findByWorld", PlotEntity.class) .setParameter("world", world) .getResultList(); - java.util.HashSet lookup = new java.util.HashSet<>(plotIds); + HashSet lookup = new HashSet<>(plotIds); for (PlotEntity p : candidates) { - if (lookup.contains(com.plotsquared.core.plot.PlotId.of(p.getPlotIdX(), p.getPlotIdZ())) && p.getId() != null) { + if (lookup.contains(PlotId.of(p.getPlotIdX(), p.getPlotIdZ())) && p.getId() != null) { ids.add(p.getId()); } } @@ -862,48 +761,43 @@ public void purgeByWorldAndPlotIds(String world, java.util.Set longIds = new java.util.HashSet<>(ids); + Set longIds = new HashSet<>(ids); // Delete child tables first - em.createQuery("DELETE FROM PlotFlagEntity f WHERE f.plot.id IN :ids") - .setParameter("ids", longIds) + em.createNamedQuery("PlotFlag.deleteAllInPlotIds") + .setParameter("plotIds", longIds) .executeUpdate(); - em.createQuery("DELETE FROM PlotMembershipEntity e WHERE e.plotId IN :ids") - .setParameter("ids", longIds) + em.createNamedQuery("PlotTrusted.deleteAllInPlotIds") + .setParameter("plotIds", longIds) .executeUpdate(); - em.createQuery("DELETE FROM PlotTrustedEntity e WHERE e.plotId IN :ids") - .setParameter("ids", longIds) + em.createNamedQuery("PlotHelper.deleteAllInPlotIds") + .setParameter("plotIds", longIds) .executeUpdate(); - em.createQuery("DELETE FROM PlotDeniedEntity e WHERE e.plotId IN :ids") - .setParameter("ids", longIds) + em.createNamedQuery("PlotDenied.deleteAllInPlotIds") + .setParameter("plotIds", longIds) .executeUpdate(); - em.createQuery("DELETE FROM PlotRatingEntity r WHERE r.plotId IN :ids") - .setParameter("ids", longIds) + em.createNamedQuery("PlotRating.deleteAllInPlotIds") + .setParameter("plotIds", longIds) .executeUpdate(); - em.createQuery("DELETE FROM PlotSettingsEntity s WHERE s.id IN :ids") - .setParameter("ids", longIds) + em.createNamedQuery("PlotSettings.deleteAllInPlotIds") + .setParameter("plotIds", longIds) .executeUpdate(); - // Finally delete plots - em.createQuery("DELETE FROM PlotEntity p WHERE p.id IN :ids") + em.createNamedQuery("Plot.deleteAllInIds") .setParameter("ids", longIds) .executeUpdate(); tx.commit(); } catch (RuntimeException e) { if (tx.isActive()) tx.rollback(); LOGGER.error("Failed to purge plots by world/id (world={}, plotIds={})", world, plotIds, e); - throw e; - } finally { - em.close(); } } @Override - public void replaceWorld(String oldWorld, String newWorld) { + public void replaceWorld(@NotNull String oldWorld, @NotNull String newWorld) { replaceWorldAll(oldWorld, newWorld); } @Override - public void replaceWorldInBounds(String oldWorld, String newWorld, com.plotsquared.core.plot.PlotId min, com.plotsquared.core.plot.PlotId max) { - if (min == null || max == null) return; + public void replaceWorldInBounds(@NotNull String oldWorld, @NotNull String newWorld, PlotId min, PlotId max) { replaceWorldInRange(oldWorld, newWorld, min.getX(), min.getY(), max.getX(), max.getY()); } } From 87f10e46806eb55e6681999346b5635ee47da55a Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 12:01:36 +0200 Subject: [PATCH 076/141] feat: remove unused import from PlotMembershipEntity for cleaner code --- .../core/persistence/entity/PlotMembershipEntity.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotMembershipEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotMembershipEntity.java index 30157c76ab..6ef457da44 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotMembershipEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotMembershipEntity.java @@ -25,7 +25,6 @@ import jakarta.persistence.NamedQueries; import jakarta.persistence.NamedQuery; import jakarta.persistence.Table; -import jdk.jfr.Name; @Entity @Table(name = "plot_helpers") From d9702f9d341603fec35aadcd49651de6730f0392 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 14:25:35 +0200 Subject: [PATCH 077/141] feat: simplify error handling and improve code readability in DBFunc by removing unnecessary try-catch blocks --- .../com/plotsquared/core/database/DBFunc.java | 475 +++++++----------- 1 file changed, 194 insertions(+), 281 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java index f10afabf9d..c7bad4850d 100644 --- a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java +++ b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java @@ -23,6 +23,7 @@ import com.plotsquared.core.persistence.entity.PlayerMetaEntity; import com.plotsquared.core.persistence.entity.PlotCommentEntity; import com.plotsquared.core.persistence.entity.PlotEntity; +import com.plotsquared.core.persistence.entity.PlotFlagEntity; import com.plotsquared.core.persistence.repository.api.ClusterHelperRepository; import com.plotsquared.core.persistence.repository.api.ClusterInvitedRepository; import com.plotsquared.core.persistence.repository.api.ClusterRepository; @@ -30,7 +31,9 @@ import com.plotsquared.core.persistence.repository.api.PlayerMetaRepository; import com.plotsquared.core.persistence.repository.api.PlotCommentRepository; import com.plotsquared.core.persistence.repository.api.PlotDeniedRepository; +import com.plotsquared.core.persistence.repository.api.PlotFlagRepository; import com.plotsquared.core.persistence.repository.api.PlotMembershipRepository; +import com.plotsquared.core.persistence.repository.api.PlotRatingRepository; import com.plotsquared.core.persistence.repository.api.PlotRepository; import com.plotsquared.core.persistence.repository.api.PlotSettingsRepository; import com.plotsquared.core.persistence.repository.api.PlotTrustedRepository; @@ -43,6 +46,7 @@ import com.plotsquared.core.plot.flag.PlotFlag; import com.plotsquared.core.util.task.RunnableVal; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -65,40 +69,29 @@ public class DBFunc { public static final UUID SERVER = UUID.fromString("00000000-0000-0000-0000-000000000000"); public static void addPersistentMeta(UUID uuid, String key, byte[] meta, boolean delete) { - try { - PlayerMetaRepository repo = PlotSquared.platform().injector().getInstance(PlayerMetaRepository.class); - if (delete) { - repo.delete(uuid.toString(), key); - } else { - repo.put(uuid.toString(), key, meta); - } - } catch (Throwable ignored) { + PlayerMetaRepository repo = PlotSquared.platform().injector().getInstance(PlayerMetaRepository.class); + if (delete) { + repo.delete(uuid.toString(), key); + } else { + repo.put(uuid.toString(), key, meta); } } public static void getPersistentMeta(UUID uuid, RunnableVal> result) { - try { - PlayerMetaRepository repo = PlotSquared.platform().injector().getInstance(PlayerMetaRepository.class); - Map map = new HashMap<>(); - for (PlayerMetaEntity e : repo.findByUuid(uuid.toString())) { - map.put(e.getKey(), e.getValue()); - } - if (result != null) { - result.run(map); - } - } catch (Throwable t) { - if (result != null) { - result.run(new HashMap<>()); - } + PlayerMetaRepository repo = PlotSquared.platform().injector().getInstance(PlayerMetaRepository.class); + Map map = new HashMap<>(); + for (PlayerMetaEntity e : repo.findByUuid(uuid.toString())) { + map.put(e.getKey(), e.getValue()); } + if (result != null) { + result.run(map); + } + } public static void removePersistentMeta(UUID uuid, String key) { - try { - PlayerMetaRepository repo = PlotSquared.platform().injector().getInstance(PlayerMetaRepository.class); - repo.delete(uuid.toString(), key); - } catch (Throwable ignored) { - } + PlayerMetaRepository repo = PlotSquared.platform().injector().getInstance(PlayerMetaRepository.class); + repo.delete(uuid.toString(), key); } public static CompletableFuture swapPlots(Plot plot1, Plot plot2) { @@ -207,16 +200,13 @@ public static void deleteTrusted(Plot plot) { * @param plot */ public static void deleteMembers(Plot plot) { - try { - PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - String world = plot.getWorldName(); - var peOpt = repo.findByWorldAndId(world, plot.getId().getX(), plot.getId().getY()); - peOpt.ifPresent(pe -> { - PlotTrustedRepository tRepo = PlotSquared.platform().injector().getInstance(PlotTrustedRepository.class); - tRepo.deleteByPlotId(pe.getId()); - }); - } catch (Throwable ignored) { - } + PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + String world = plot.getWorldName(); + var peOpt = repo.findByWorldAndId(world, plot.getId().getX(), plot.getId().getY()); + peOpt.ifPresent(pe -> { + PlotTrustedRepository tRepo = PlotSquared.platform().injector().getInstance(PlotTrustedRepository.class); + tRepo.deleteByPlotId(pe.getId()); + }); } /** @@ -225,16 +215,13 @@ public static void deleteMembers(Plot plot) { * @param plot */ public static void deleteDenied(Plot plot) { - try { - PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - String world = plot.getWorldName(); - var peOpt = repo.findByWorldAndId(world, plot.getId().getX(), plot.getId().getY()); - peOpt.ifPresent(pe -> { - PlotDeniedRepository dRepo = PlotSquared.platform().injector().getInstance(PlotDeniedRepository.class); - dRepo.deleteByPlotId(pe.getId()); - }); - } catch (Throwable ignored) { - } + PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + String world = plot.getWorldName(); + var peOpt = repo.findByWorldAndId(world, plot.getId().getX(), plot.getId().getY()); + peOpt.ifPresent(pe -> { + PlotDeniedRepository dRepo = PlotSquared.platform().injector().getInstance(PlotDeniedRepository.class); + dRepo.deleteByPlotId(pe.getId()); + }); } /** @@ -243,13 +230,10 @@ public static void deleteDenied(Plot plot) { * @param plot */ public static void deleteComments(Plot plot) { - try { - PlotCommentRepository repo = PlotSquared.platform().injector().getInstance(PlotCommentRepository.class); - String world = plot.getWorldName(); - int hash = plot.getId().hashCode(); - repo.deleteByWorldAndHash(world, hash); - } catch (Throwable ignored) { - } + PlotCommentRepository repo = PlotSquared.platform().injector().getInstance(PlotCommentRepository.class); + String world = plot.getWorldName(); + int hash = plot.getId().hashCode(); + repo.deleteByWorldAndHash(world, hash); } /** @@ -262,34 +246,27 @@ public static void deleteComments(Plot plot) { * @param plot */ public static void deleteSettings(Plot plot) { - - try { - PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - String world = plot.getWorldName(); - var peOpt = repo.findByWorldAndId(world, plot.getId().getX(), plot.getId().getY()); - peOpt.ifPresent(pe -> { - PlotSettingsRepository sRepo = PlotSquared.platform().injector().getInstance(PlotSettingsRepository.class); - sRepo.deleteByPlotId(pe.getId()); - }); - } catch (Throwable ignored) { - } + PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + String world = plot.getWorldName(); + var peOpt = repo.findByWorldAndId(world, plot.getId().getX(), plot.getId().getY()); + peOpt.ifPresent(pe -> { + PlotSettingsRepository sRepo = PlotSquared.platform().injector().getInstance(PlotSettingsRepository.class); + sRepo.deleteByPlotId(pe.getId()); + }); } public static void delete(PlotCluster toDelete) { if (toDelete == null) { return; } - try { - ClusterRepository clusterRepo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); - String world = toDelete.area != null ? toDelete.area.getWorldName() : null; - if (world == null) { - return; - } - PlotId center = toDelete.getCenterPlotId(); - java.util.Optional ce = clusterRepo.findByWorldAndBounds(world, center.getX(), center.getY()); - ce.ifPresent(entity -> clusterRepo.deleteById(entity.getId())); - } catch (Throwable ignored) { + ClusterRepository clusterRepo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); + String world = toDelete.area != null ? toDelete.area.getWorldName() : null; + if (world == null) { + return; } + PlotId center = toDelete.getCenterPlotId(); + Optional ce = clusterRepo.findByWorldAndBounds(world, center.getX(), center.getY()); + ce.ifPresent(entity -> clusterRepo.deleteById(entity.getId())); } /** @@ -299,11 +276,8 @@ public static void delete(PlotCluster toDelete) { * @param plot Plot Object */ public static void createPlotSettings(int id, Plot plot) { - try { - PlotSettingsRepository repo = PlotSquared.platform().injector().getInstance(PlotSettingsRepository.class); - repo.createDefaultIfAbsent(id, "DEFAULT"); - } catch (Throwable ignored) { - } + PlotSettingsRepository repo = PlotSquared.platform().injector().getInstance(PlotSettingsRepository.class); + repo.createDefaultIfAbsent(id, "DEFAULT"); } /** @@ -318,63 +292,54 @@ public static void setMerged(Plot plot, boolean[] merged) { if (plot == null || merged == null) { return; } - try { - PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - PlotSettingsRepository settingsRepo = PlotSquared.platform().injector().getInstance(PlotSettingsRepository.class); - String world = plot.getWorldName(); - int x = plot.getId().getX(); - int z = plot.getId().getY(); - Optional pe = plotRepo.findByWorldAndId(world, x, z); - pe.ifPresent(entity -> { - int mask = com.plotsquared.core.util.HashUtil.hash(merged); - settingsRepo.updateMerged(entity.getId(), mask); - }); - } catch (Throwable ignored) { - } + PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + PlotSettingsRepository settingsRepo = PlotSquared.platform().injector().getInstance(PlotSettingsRepository.class); + String world = plot.getWorldName(); + int x = plot.getId().getX(); + int z = plot.getId().getY(); + Optional pe = plotRepo.findByWorldAndId(world, x, z); + pe.ifPresent(entity -> { + int mask = com.plotsquared.core.util.HashUtil.hash(merged); + settingsRepo.updateMerged(entity.getId(), mask); + }); } public static void setFlag(Plot plot, PlotFlag flag) { if (plot == null || flag == null) { return; } - try { - PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - com.plotsquared.core.persistence.repository.api.PlotFlagRepository flagRepo = PlotSquared.platform().injector().getInstance(com.plotsquared.core.persistence.repository.api.PlotFlagRepository.class); - Optional pe = plotRepo.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); - pe.ifPresent(entity -> { - long plotId = entity.getId(); - String name = flag.getName(); - String value = flag.toString(); - var existing = flagRepo.findByPlotAndName(plotId, name); - if (existing.isPresent()) { - var e = existing.get(); - e.setValue(value); - flagRepo.save(e); - } else { - com.plotsquared.core.persistence.entity.PlotFlagEntity e = new com.plotsquared.core.persistence.entity.PlotFlagEntity(); - com.plotsquared.core.persistence.entity.PlotEntity pref = new com.plotsquared.core.persistence.entity.PlotEntity(); - pref.setId(entity.getId()); - e.setPlot(pref); - e.setFlag(name); - e.setValue(value); - flagRepo.save(e); - } - }); - } catch (Throwable ignored) { - } + PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + PlotFlagRepository flagRepo = PlotSquared.platform().injector().getInstance(PlotFlagRepository.class); + Optional pe = plotRepo.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); + pe.ifPresent(entity -> { + long plotId = entity.getId(); + String name = flag.getName(); + String value = flag.toString(); + var existing = flagRepo.findByPlotAndName(plotId, name); + if (existing.isPresent()) { + var e = existing.get(); + e.setValue(value); + flagRepo.save(e); + } else { + PlotFlagEntity e = new PlotFlagEntity(); + PlotEntity pref = new PlotEntity(); + pref.setId(entity.getId()); + e.setPlot(pref); + e.setFlag(name); + e.setValue(value); + flagRepo.save(e); + } + }); } public static void removeFlag(Plot plot, PlotFlag flag) { if (plot == null || flag == null) { return; } - try { - PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - com.plotsquared.core.persistence.repository.api.PlotFlagRepository flagRepo = PlotSquared.platform().injector().getInstance(com.plotsquared.core.persistence.repository.api.PlotFlagRepository.class); - Optional pe = plotRepo.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); - pe.ifPresent(entity -> flagRepo.deleteByPlotAndName(entity.getId(), flag.getName())); - } catch (Throwable ignored) { - } + PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + PlotFlagRepository flagRepo = PlotSquared.platform().injector().getInstance(PlotFlagRepository.class); + Optional pe = plotRepo.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); + pe.ifPresent(entity -> flagRepo.deleteByPlotAndName(entity.getId(), flag.getName())); } /** @@ -385,29 +350,20 @@ public static void setAlias(Plot plot, String alias) { if (plot == null) { return; } - try { - PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - PlotSettingsRepository settingsRepo = PlotSquared.platform().injector().getInstance(PlotSettingsRepository.class); - Optional pe = plotRepo.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); - pe.ifPresent(entity -> settingsRepo.updateAlias(entity.getId(), alias)); - } catch (Throwable ignored) { - } + PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + PlotSettingsRepository settingsRepo = PlotSquared.platform().injector().getInstance(PlotSettingsRepository.class); + Optional pe = plotRepo.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); + pe.ifPresent(entity -> settingsRepo.updateAlias(entity.getId(), alias)); } public static void purgeIds(Set uniqueIds) { - try { - PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - plotRepo.purgeIds(uniqueIds); - } catch (Throwable ignored) { - } + PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + plotRepo.purgeIds(uniqueIds); } public static void purge(PlotArea area, Set plotIds) { - try { - PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - plotRepo.purgeByWorldAndPlotIds(area.getWorldName(), plotIds); - } catch (Throwable ignored) { - } + PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + plotRepo.purgeByWorldAndPlotIds(area.getWorldName(), plotIds); } /** @@ -418,13 +374,10 @@ public static void setPosition(Plot plot, String position) { if (plot == null || position == null) { return; } - try { - PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - PlotSettingsRepository settingsRepo = PlotSquared.platform().injector().getInstance(PlotSettingsRepository.class); - Optional pe = plotRepo.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); - pe.ifPresent(entity -> settingsRepo.updatePosition(entity.getId(), position)); - } catch (Throwable ignored) { - } + PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + PlotSettingsRepository settingsRepo = PlotSquared.platform().injector().getInstance(PlotSettingsRepository.class); + Optional pe = plotRepo.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); + pe.ifPresent(entity -> settingsRepo.updatePosition(entity.getId(), position)); } /** @@ -432,26 +385,18 @@ public static void setPosition(Plot plot, String position) { * @param comment */ public static void removeComment(Plot plot, PlotComment comment) { - try { - PlotCommentRepository repo = PlotSquared.platform().injector().getInstance(PlotCommentRepository.class); - String world = plot.getWorldName(); - int hash = plot.getId().hashCode(); - repo.deleteOne(world, hash, comment.inbox(), comment.senderName(), comment.comment()); - } catch (Throwable ignored) { - } + PlotCommentRepository repo = PlotSquared.platform().injector().getInstance(PlotCommentRepository.class); + String world = plot.getWorldName(); + int hash = plot.getId().hashCode(); + repo.deleteOne(world, hash, comment.inbox(), comment.senderName(), comment.comment()); } public static void clearInbox(Plot plot, String inbox) { - try { - PlotCommentRepository repo = PlotSquared.platform().injector().getInstance(PlotCommentRepository.class); - if (plot != null) { - String world = plot.getWorldName(); - int hash = plot.getId().hashCode(); - repo.clearInbox(world, hash, inbox); - } else { - // Fallback: no plot provided; unable to infer world. No-op to avoid unintended global deletions. - } - } catch (Throwable ignored) { + PlotCommentRepository repo = PlotSquared.platform().injector().getInstance(PlotCommentRepository.class); + if (plot != null) { + String world = plot.getWorldName(); + int hash = plot.getId().hashCode(); + repo.clearInbox(world, hash, inbox); } } @@ -460,19 +405,16 @@ public static void clearInbox(Plot plot, String inbox) { * @param comment */ public static void setComment(Plot plot, PlotComment comment) { - try { - PlotCommentRepository repo = PlotSquared.platform().injector().getInstance(PlotCommentRepository.class); - if (plot != null) { - PlotCommentEntity entity = new PlotCommentEntity(); - entity.setWorld(plot.getWorldName()); - entity.setHashcode(plot.getId().hashCode()); - entity.setComment(comment.comment()); - entity.setInbox(comment.inbox()); - entity.setTimestamp((int) (comment.timestamp() / 1000)); - entity.setSender(comment.senderName()); - repo.save(entity); - } - } catch (Throwable ignored) { + PlotCommentRepository repo = PlotSquared.platform().injector().getInstance(PlotCommentRepository.class); + if (plot != null) { + PlotCommentEntity entity = new PlotCommentEntity(); + entity.setWorld(plot.getWorldName()); + entity.setHashcode(plot.getId().hashCode()); + entity.setComment(comment.comment()); + entity.setInbox(comment.inbox()); + entity.setTimestamp((int) (comment.timestamp() / 1000)); + entity.setSender(comment.senderName()); + repo.save(entity); } } @@ -483,26 +425,20 @@ public static void getComments( Plot plot, String inbox, RunnableVal> whenDone ) { - try { - PlotCommentRepository repo = PlotSquared.platform().injector().getInstance(PlotCommentRepository.class); - List out = new java.util.ArrayList<>(); - if (plot != null) { - String world = plot.getWorldName(); - int hash = plot.getId().hashCode(); - for (PlotCommentEntity e : repo.findByWorldHashAndInbox(world, hash, inbox)) { - PlotId id = (e.getHashcode() != null && e.getHashcode() != 0) ? PlotId.unpair(e.getHashcode()) : null; - long tsMillis = e.getTimestamp() != null ? e.getTimestamp().longValue() * 1000L : 0L; - out.add(new PlotComment(e.getWorld(), id, e.getComment(), e.getSender(), e.getInbox(), tsMillis)); - } - } - if (whenDone != null) { - whenDone.run(out); - } - } catch (Throwable t) { - if (whenDone != null) { - whenDone.run(java.util.Collections.emptyList()); + PlotCommentRepository repo = PlotSquared.platform().injector().getInstance(PlotCommentRepository.class); + List out = new ArrayList<>(); + if (plot != null) { + String world = plot.getWorldName(); + int hash = plot.getId().hashCode(); + for (PlotCommentEntity e : repo.findByWorldHashAndInbox(world, hash, inbox)) { + PlotId id = (e.getHashcode() != null && e.getHashcode() != 0) ? PlotId.unpair(e.getHashcode()) : null; + long tsMillis = e.getTimestamp() != null ? e.getTimestamp().longValue() * 1000L : 0L; + out.add(new PlotComment(e.getWorld(), id, e.getComment(), e.getSender(), e.getInbox(), tsMillis)); } } + if (whenDone != null) { + whenDone.run(out); + } } /** @@ -513,17 +449,14 @@ public static void removeTrusted(Plot plot, UUID uuid) { if (plot == null) { return; } - try { - PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - PlotTrustedRepository trustedRepo = PlotSquared.platform().injector().getInstance(PlotTrustedRepository.class); - String world = plot.getArea().toString(); - int x = plot.getId().getX(); - int z = plot.getId().getY(); - java.util.Optional ent = plotRepo.findByWorldAndId(world, x, z); - if (ent.isPresent() && ent.get().getId() != null) { - trustedRepo.remove(ent.get().getId(), uuid.toString()); - } - } catch (Throwable ignored) { + PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + PlotTrustedRepository trustedRepo = PlotSquared.platform().injector().getInstance(PlotTrustedRepository.class); + String world = plot.getArea().toString(); + int x = plot.getId().getX(); + int z = plot.getId().getY(); + java.util.Optional ent = plotRepo.findByWorldAndId(world, x, z); + if (ent.isPresent() && ent.get().getId() != null) { + trustedRepo.remove(ent.get().getId(), uuid.toString()); } } @@ -535,18 +468,15 @@ public static void removeHelper(PlotCluster cluster, UUID uuid) { if (cluster == null || uuid == null) { return; } - try { - ClusterRepository clusterRepo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); - ClusterHelperRepository helperRepo = PlotSquared.platform().injector().getInstance(ClusterHelperRepository.class); - String world = cluster.area != null ? cluster.area.toString() : null; - PlotId center = cluster.getCenterPlotId(); - if (world != null) { - Optional ent = clusterRepo.findByWorldAndBounds(world, center.getX(), center.getY()); - if (ent.isPresent() && ent.get().getId() != null) { - helperRepo.remove(ent.get().getId(), uuid.toString()); - } + ClusterRepository clusterRepo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); + ClusterHelperRepository helperRepo = PlotSquared.platform().injector().getInstance(ClusterHelperRepository.class); + String world = cluster.area != null ? cluster.area.toString() : null; + PlotId center = cluster.getCenterPlotId(); + if (world != null) { + Optional ent = clusterRepo.findByWorldAndBounds(world, center.getX(), center.getY()); + if (ent.isPresent() && ent.get().getId() != null) { + helperRepo.remove(ent.get().getId(), uuid.toString()); } - } catch (Throwable ignored) { } } @@ -557,23 +487,19 @@ public static void createCluster(PlotCluster cluster) { if (cluster == null) { return; } - try { - ClusterRepository repo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); - ClusterEntity e = new ClusterEntity(); - e.setWorld(cluster.area != null ? cluster.area.toString() : null); - e.setOwner(cluster.owner != null ? cluster.owner.toString() : null); - if (cluster.getP1() != null) { - e.setPos1X(cluster.getP1().getX()); - e.setPos1Z(cluster.getP1().getY()); - } - if (cluster.getP2() != null) { - e.setPos2X(cluster.getP2().getX()); - e.setPos2Z(cluster.getP2().getY()); - } - repo.save(e); - // Do not assign cluster.temp; avoid reassigning transient identifiers - } catch (Throwable ignored) { + ClusterRepository repo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); + ClusterEntity e = new ClusterEntity(); + e.setWorld(cluster.area != null ? cluster.area.toString() : null); + e.setOwner(cluster.owner != null ? cluster.owner.toString() : null); + if (cluster.getP1() != null) { + e.setPos1X(cluster.getP1().getX()); + e.setPos1Z(cluster.getP1().getY()); } + if (cluster.getP2() != null) { + e.setPos2X(cluster.getP2().getX()); + e.setPos2Z(cluster.getP2().getY()); + } + repo.save(e); } /** @@ -585,22 +511,19 @@ public static void resizeCluster(PlotCluster current, PlotId min, PlotId max) { if (current == null || min == null || max == null) { return; } - try { - ClusterRepository repo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); - String world = current.area != null ? current.area.toString() : null; - PlotId center = current.getCenterPlotId(); - if (world != null) { - Optional ent = repo.findByWorldAndBounds(world, center.getX(), center.getY()); - if (ent.isPresent()) { - ClusterEntity e = ent.get(); - e.setPos1X(min.getX()); - e.setPos1Z(min.getY()); - e.setPos2X(max.getX()); - e.setPos2Z(max.getY()); - repo.save(e); - } + ClusterRepository repo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); + String world = current.area != null ? current.area.toString() : null; + PlotId center = current.getCenterPlotId(); + if (world != null) { + Optional ent = repo.findByWorldAndBounds(world, center.getX(), center.getY()); + if (ent.isPresent()) { + ClusterEntity e = ent.get(); + e.setPos1X(min.getX()); + e.setPos1Z(min.getY()); + e.setPos2X(max.getX()); + e.setPos2Z(max.getY()); + repo.save(e); } - } catch (Throwable ignored) { } } @@ -704,51 +627,41 @@ public static void setDenied(Plot plot, UUID uuid) { if (plot == null || uuid == null) { return; } - try { - PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - PlotDeniedRepository deniedRepo = PlotSquared.platform().injector().getInstance(PlotDeniedRepository.class); - String world = plot.getArea().toString(); - PlotId pid = plot.getId(); - Optional pe = plotRepo.findByWorldAndId(world, pid.getX(), pid.getY()); - pe.ifPresent(entity -> deniedRepo.add(entity.getId(), uuid.toString())); - } catch (Throwable ignored) { - } + PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + PlotDeniedRepository deniedRepo = PlotSquared.platform().injector().getInstance(PlotDeniedRepository.class); + String world = plot.getArea().toString(); + PlotId pid = plot.getId(); + Optional pe = plotRepo.findByWorldAndId(world, pid.getX(), pid.getY()); + pe.ifPresent(entity -> deniedRepo.add(entity.getId(), uuid.toString())); } public static HashMap getRatings(Plot plot) { if (plot == null) { return new HashMap<>(0); } - try { - PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - com.plotsquared.core.persistence.repository.api.PlotRatingRepository ratingRepo = PlotSquared.platform().injector().getInstance(com.plotsquared.core.persistence.repository.api.PlotRatingRepository.class); - Optional pe = plotRepo.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); - HashMap out = new HashMap<>(); - pe.ifPresent(entity -> { - for (com.plotsquared.core.persistence.entity.PlotRatingEntity e : ratingRepo.findByPlotId(entity.getId())) { - try { - out.put(UUID.fromString(e.getPlayer()), e.getRating()); - } catch (IllegalArgumentException ignored) { - } + PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + PlotRatingRepository ratingRepo = PlotSquared.platform().injector().getInstance(PlotRatingRepository.class); + Optional pe = plotRepo.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); + HashMap out = new HashMap<>(); + pe.ifPresent(entity -> { + for (com.plotsquared.core.persistence.entity.PlotRatingEntity e : ratingRepo.findByPlotId(entity.getId())) { + try { + out.put(UUID.fromString(e.getPlayer()), e.getRating()); + } catch (IllegalArgumentException ignored) { } - }); - return out; - } catch (Throwable ignored) { - return new HashMap<>(0); - } + } + }); + return out; } public static void setRating(Plot plot, UUID rater, int value) { if (plot == null || rater == null) { return; } - try { - PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - com.plotsquared.core.persistence.repository.api.PlotRatingRepository ratingRepo = PlotSquared.platform().injector().getInstance(com.plotsquared.core.persistence.repository.api.PlotRatingRepository.class); - Optional pe = plotRepo.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); - pe.ifPresent(entity -> ratingRepo.upsert(entity.getId(), rater.toString(), value)); - } catch (Throwable ignored) { - } + PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); + PlotRatingRepository ratingRepo = PlotSquared.platform().injector().getInstance(PlotRatingRepository.class); + Optional pe = plotRepo.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); + pe.ifPresent(entity -> ratingRepo.upsert(entity.getId(), rater.toString(), value)); } public static HashMap> getClusters() { From da3ecb1960e0aacee0058163d81868a149ca48a2 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 14:32:25 +0200 Subject: [PATCH 078/141] feat: remove unused import from DBFunc for cleaner code --- Core/src/main/java/com/plotsquared/core/database/DBFunc.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java index c7bad4850d..bed13cdc35 100644 --- a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java +++ b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java @@ -37,7 +37,6 @@ import com.plotsquared.core.persistence.repository.api.PlotRepository; import com.plotsquared.core.persistence.repository.api.PlotSettingsRepository; import com.plotsquared.core.persistence.repository.api.PlotTrustedRepository; -import com.plotsquared.core.persistence.repository.api.ClusterSettingsRepository; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotCluster; From a145f0b4a9aca92bbf96b2f3762a31e2264ba389 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 14:46:13 +0200 Subject: [PATCH 079/141] feat: update version to 8.0.0-SNAPSHOT for upcoming release --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index ef652ad7d2..153a49443c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -20,7 +20,7 @@ plugins { } group = "com.intellectualsites.plotsquared" -version = "7.5.7-SNAPSHOT" +version = "8.0.0-SNAPSHOT" if (!File("$rootDir/.git").exists()) { logger.lifecycle(""" From 35039be38017be7644c6ddfb19858d9d083c2034 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 15:12:01 +0200 Subject: [PATCH 080/141] feat: update database dependencies to use Liquibase and HikariCP --- Core/build.gradle.kts | 6 +++--- gradle/libs.versions.toml | 8 +++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Core/build.gradle.kts b/Core/build.gradle.kts index 5f17bb15a1..5bd5a8b0ce 100644 --- a/Core/build.gradle.kts +++ b/Core/build.gradle.kts @@ -47,12 +47,12 @@ dependencies { // Database api(libs.hibernateCore) + api(libs.hibernateHikariCp) + api(libs.hikari) runtimeOnly(libs.jaxbRuntime) - annotationProcessor(libs.hibernateCore) api(libs.hibernateCommunityDialects) api(libs.jpaApi) - api(libs.flywayCore) - runtimeOnly(libs.flywayMysql) + api(libs.liquibaseCore) runtimeOnly(libs.mariadbJavaClient) runtimeOnly(libs.sqliteJdbc) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1cedfac10e..d73e094e6a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -35,7 +35,8 @@ serverlib = "2.3.7" # Database jpa-api = "3.2.0" hibernate-core = "7.1.0.Final" -flyway-core = "11.11.2" +liquibase-core = "4.33.0" +hikari = "7.0.2" jaxbRuntime = "4.0.5" # JDBC Drivers mariadb-java-client = "3.5.5" @@ -89,9 +90,10 @@ serverlib = { group = "dev.notmyfault.serverlib", name = "ServerLib", version.re # Database jpaApi = { group = "jakarta.persistence", name = "jakarta.persistence-api", version.ref = "jpa-api" } hibernateCore = { group = "org.hibernate.orm", name = "hibernate-core", version.ref = "hibernate-core" } +hikari = { group = "com.zaxxer", name = "HikariCP", version.ref = "hikari" } +hibernateHikariCp = { group = "org.hibernate.orm", name = "hibernate-hikaricp", version.ref = "hibernate-core" } hibernateCommunityDialects = { group = "org.hibernate.orm", name = "hibernate-community-dialects", version.ref = "hibernate-core" } -flywayCore = { group = "org.flywaydb", name = "flyway-core", version.ref = "flyway-core" } -flywayMysql = { group = "org.flywaydb", name = "flyway-mysql", version.ref = "flyway-core" } +liquibaseCore = { group = "org.liquibase", name = "liquibase-core", version.ref = "liquibase-core" } jaxbRuntime = { group = "org.glassfish.jaxb", name = "jaxb-runtime", version.ref = "jaxbRuntime" } # JDBC Drivers mariadbJavaClient = { group = "org.mariadb.jdbc", name = "mariadb-java-client", version.ref = "mariadb-java-client" } From ebf62525286db259f02309348c83e7ec23e6ba9e Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 15:12:15 +0200 Subject: [PATCH 081/141] feat: implement DataSourceProvider and DatabaseMigrationService for Liquibase integration --- .../config/DataSourceProvider.java | 85 +++++++ .../config/DatabaseMigrationService.java | 214 ++++++++++++++++++ .../persistence/config/FlywayBootstrap.java | 48 ---- .../config/JpaPropertiesProvider.java | 4 +- .../config/LiquibaseBootstrap.java | 66 ++++++ .../persistence/config/PersistenceModule.java | 51 ++--- 6 files changed, 380 insertions(+), 88 deletions(-) create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/config/DataSourceProvider.java create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/config/DatabaseMigrationService.java delete mode 100644 Core/src/main/java/com/plotsquared/core/persistence/config/FlywayBootstrap.java create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseBootstrap.java diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/DataSourceProvider.java b/Core/src/main/java/com/plotsquared/core/persistence/config/DataSourceProvider.java new file mode 100644 index 0000000000..3187bfb6c0 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/DataSourceProvider.java @@ -0,0 +1,85 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.config; + +import com.google.inject.Singleton; +import com.plotsquared.core.configuration.Storage; +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; + +import javax.sql.DataSource; +import java.util.logging.Logger; + +/** + * Provides configured DataSource instances for database connections. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +@Singleton +public final class DataSourceProvider { + private static final Logger LOGGER = Logger.getLogger(DataSourceProvider.class.getName()); + + /** + * Creates a DataSource based on current storage configuration. + */ + public DataSource createDataSource() { + HikariConfig config = new HikariConfig(); + + if (Storage.MySQL.USE) { + String url = "jdbc:mysql://" + Storage.MySQL.HOST + ":" + Storage.MySQL.PORT + "/" + Storage.MySQL.DATABASE + + "?" + String.join("&", Storage.MySQL.PROPERTIES); + config.setJdbcUrl(url); + config.setUsername(Storage.MySQL.USER); + config.setPassword(Storage.MySQL.PASSWORD); + config.setDriverClassName("com.mysql.cj.jdbc.Driver"); + } else if (Storage.SQLite.USE) { + String url = "jdbc:sqlite:" + Storage.SQLite.DB + ".db"; + config.setJdbcUrl(url); + config.setDriverClassName("org.sqlite.JDBC"); + } + + config.setMaximumPoolSize(10); + config.setMinimumIdle(2); + config.setConnectionTimeout(30000); + config.setIdleTimeout(600000); + config.setLeakDetectionThreshold(60000); + + return new HikariDataSource(config); + } + + /** + * Creates a DataSource for a specific database configuration (used for migration between databases). + */ + public DataSource createDataSource(String jdbcUrl, String username, String password, String driverClass) { + HikariConfig config = new HikariConfig(); + config.setJdbcUrl(jdbcUrl); + if (username != null) config.setUsername(username); + if (password != null) config.setPassword(password); + config.setDriverClassName(driverClass); + + config.setMaximumPoolSize(5); + config.setMinimumIdle(1); + config.setConnectionTimeout(30000); + + return new HikariDataSource(config); + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/DatabaseMigrationService.java b/Core/src/main/java/com/plotsquared/core/persistence/config/DatabaseMigrationService.java new file mode 100644 index 0000000000..ae27cd631d --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/DatabaseMigrationService.java @@ -0,0 +1,214 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.config; + +import com.google.inject.Singleton; +import com.plotsquared.core.configuration.Storage; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; + +/** + * Service for handling database migrations between different PlotSquared versions + * and database systems (SQLite <-> MySQL). + * + * Note: v7 to v8 migration is now handled completely by Liquibase changesets. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +@Singleton +public final class DatabaseMigrationService { + private static final Logger LOGGER = Logger.getLogger(DatabaseMigrationService.class.getName()); + + /** + * Checks if the current database is using the v7 schema format. + * This is now mainly used for informational purposes since Liquibase handles the migration. + */ + public boolean isV7Database(Connection connection) throws SQLException { + String prefix = Storage.PREFIX == null ? "" : Storage.PREFIX; + DatabaseMetaData metaData = connection.getMetaData(); + + try (ResultSet tables = metaData.getTables(null, null, prefix + "plot", new String[]{"TABLE"})) { + if (!tables.next()) { + // No plot table exists, assume new installation + return false; + } + } + + // Check if the plot table has v7 structure (no auto-increment ID column) + try (ResultSet columns = metaData.getColumns(null, null, prefix + "plot", null)) { + boolean hasIdColumn = false; + boolean hasV7Columns = false; + + while (columns.next()) { + String columnName = columns.getString("COLUMN_NAME"); + if ("id".equalsIgnoreCase(columnName)) { + hasIdColumn = true; + } + if ("plot_id_x".equalsIgnoreCase(columnName) || "plot_id_z".equalsIgnoreCase(columnName)) { + hasV7Columns = true; + } + } + + // v7 has plot_id_x/plot_id_z but no auto-increment ID column + // v8 has both the coordinates AND an auto-increment ID column + return hasV7Columns && !hasIdColumn; + } + } + + /** + * Gets the current database version information. + */ + public String getDatabaseVersion(Connection connection) throws SQLException { + if (isV7Database(connection)) { + return "v7 (will be migrated to v8 by Liquibase)"; + } else { + String prefix = Storage.PREFIX == null ? "" : Storage.PREFIX; + try (ResultSet tables = connection.getMetaData().getTables(null, null, prefix + "plot", new String[]{"TABLE"})) { + if (tables.next()) { + return "v8"; + } else { + return "new installation"; + } + } + } + } + + /** + * Migrates data from one database type to another (e.g., SQLite to MySQL). + * This is the main functionality remaining in this service since schema migration + * is now handled by Liquibase. + */ + public void migrateBetweenDatabaseTypes(Connection sourceConnection, Connection targetConnection) throws SQLException { + LOGGER.info("Starting cross-database migration..."); + + try { + targetConnection.setAutoCommit(false); + + String prefix = Storage.PREFIX == null ? "" : Storage.PREFIX; + + // Get all tables from source database + List tablesToMigrate = getExistingTables(sourceConnection, prefix); + + for (String tableName : tablesToMigrate) { + migrateTable(sourceConnection, targetConnection, tableName); + } + + targetConnection.commit(); + LOGGER.info("Cross-database migration completed successfully."); + + } catch (SQLException e) { + targetConnection.rollback(); + LOGGER.severe("Cross-database migration failed: " + e.getMessage()); + throw e; + } finally { + targetConnection.setAutoCommit(true); + } + } + + private List getExistingTables(Connection connection, String prefix) throws SQLException { + List tables = new ArrayList<>(); + DatabaseMetaData metaData = connection.getMetaData(); + + try (ResultSet rs = metaData.getTables(null, null, prefix + "%", new String[]{"TABLE"})) { + while (rs.next()) { + String tableName = rs.getString("TABLE_NAME"); + // Skip backup and temporary tables, and Liquibase tables + if (!tableName.contains("_backup_") && !tableName.contains("_v7_temp") && + !tableName.contains("DATABASECHANGELOG")) { + tables.add(tableName); + } + } + } + + return tables; + } + + private void migrateTable(Connection source, Connection target, String tableName) throws SQLException { + LOGGER.info("Migrating table: " + tableName); + + // First, clear the target table + try (Statement stmt = target.createStatement()) { + stmt.execute("DELETE FROM " + tableName); + } + + // Get all data from source table + try (Statement sourceStmt = source.createStatement(); + ResultSet rs = sourceStmt.executeQuery("SELECT * FROM " + tableName)) { + + if (!rs.next()) { + LOGGER.info("Table " + tableName + " is empty, skipping"); + return; + } + + // Get column metadata + int columnCount = rs.getMetaData().getColumnCount(); + List columnNames = new ArrayList<>(); + for (int i = 1; i <= columnCount; i++) { + columnNames.add(rs.getMetaData().getColumnName(i)); + } + + // Build insert statement + StringBuilder insertQuery = new StringBuilder("INSERT INTO " + tableName + " ("); + insertQuery.append(String.join(", ", columnNames)); + insertQuery.append(") VALUES ("); + for (int i = 0; i < columnCount; i++) { + if (i > 0) insertQuery.append(", "); + insertQuery.append("?"); + } + insertQuery.append(")"); + + try (PreparedStatement insertStmt = target.prepareStatement(insertQuery.toString())) { + rs.beforeFirst(); + + int count = 0; + while (rs.next()) { + for (int i = 1; i <= columnCount; i++) { + insertStmt.setObject(i, rs.getObject(i)); + } + insertStmt.addBatch(); + + if (++count % 1000 == 0) { + insertStmt.executeBatch(); + } + } + + insertStmt.executeBatch(); + LOGGER.info("Migrated " + count + " rows from table " + tableName); + } + } + } + + private boolean tableExists(Connection connection, String tableName) throws SQLException { + DatabaseMetaData metaData = connection.getMetaData(); + try (ResultSet tables = metaData.getTables(null, null, tableName, new String[]{"TABLE"})) { + return tables.next(); + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/FlywayBootstrap.java b/Core/src/main/java/com/plotsquared/core/persistence/config/FlywayBootstrap.java deleted file mode 100644 index 42aae38c71..0000000000 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/FlywayBootstrap.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.core.persistence.config; - -import com.google.inject.Inject; -import com.google.inject.Singleton; -import org.flywaydb.core.Flyway; - -import java.util.logging.Logger; - -/** - * Eager bootstrap that executes Flyway migrations during application startup. - * - * @since 8.0.0 - * @version 1.0.0 - * @author TheMeinerLP - * @author IntellectualSites - */ -@Singleton -public final class FlywayBootstrap { - private static final Logger LOGGER = Logger.getLogger(FlywayBootstrap.class.getName()); - - @Inject - public FlywayBootstrap(Flyway flyway) { - try { - flyway.migrate(); - LOGGER.info("Flyway migration complete."); - } catch (Exception e) { - LOGGER.severe("Flyway migration failed: " + e.getMessage()); - } - } -} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java b/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java index 210c12228d..3ca46bd4ae 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java @@ -56,8 +56,8 @@ public Map getProperties() { props.put("hibernate.dialect", "org.hibernate.community.dialect.SQLiteDialect"); } - // Schema is managed by Flyway; only validate with Hibernate - props.put("hibernate.hbm2ddl.auto", "create"); + // Schema is managed by Liquibase; only validate with Hibernate + props.put("hibernate.hbm2ddl.auto", "validate"); props.put("hibernate.show_sql", false); props.put("hibernate.format_sql", false); diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseBootstrap.java b/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseBootstrap.java new file mode 100644 index 0000000000..fc601eebe9 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseBootstrap.java @@ -0,0 +1,66 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.config; + +import com.google.inject.Inject; +import com.google.inject.Singleton; +import liquibase.Liquibase; +import liquibase.database.Database; +import liquibase.database.DatabaseFactory; +import liquibase.database.jvm.JdbcConnection; +import liquibase.resource.ClassLoaderResourceAccessor; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.util.logging.Logger; + +/** + * Eager bootstrap that executes Liquibase migrations during application startup. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +@Singleton +public final class LiquibaseBootstrap { + private static final Logger LOGGER = Logger.getLogger(LiquibaseBootstrap.class.getName()); + + @Inject + public LiquibaseBootstrap(DataSource dataSource, DatabaseMigrationService migrationService) { + try (Connection connection = dataSource.getConnection()) { + Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection)); + + // Log database version information + String dbVersion = migrationService.getDatabaseVersion(connection); + LOGGER.info("Detected database version: " + dbVersion); + + // Run Liquibase migrations - this will handle both v7->v8 migration and new v8 installations + Liquibase liquibase = new Liquibase("db/changelog/db.changelog-master.xml", + new ClassLoaderResourceAccessor(), database); + + liquibase.update(""); + LOGGER.info("Liquibase migration completed successfully."); + + } catch (Exception e) { + LOGGER.severe("Liquibase migration failed: " + e.getMessage()); + throw new RuntimeException("Database migration failed", e); + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java b/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java index 6de6b75cff..eaea7ce343 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java @@ -21,7 +21,6 @@ import com.google.inject.AbstractModule; import com.google.inject.Provides; import com.google.inject.Singleton; -import com.plotsquared.core.configuration.Storage; import com.plotsquared.core.persistence.repository.api.ClusterHelperRepository; import com.plotsquared.core.persistence.repository.api.ClusterInvitedRepository; import com.plotsquared.core.persistence.repository.api.ClusterRepository; @@ -51,8 +50,8 @@ import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManagerFactory; import jakarta.persistence.Persistence; -import org.flywaydb.core.Flyway; +import javax.sql.DataSource; import java.util.Map; import java.util.function.Supplier; @@ -82,10 +81,20 @@ protected void configure() { bind(ClusterHelperRepository.class).to(ClusterHelperRepositoryJpa.class); bind(ClusterInvitedRepository.class).to(ClusterInvitedRepositoryJpa.class); bind(ClusterSettingsRepository.class).to(ClusterSettingsRepositoryJpa.class); + + // Bind configuration and migration services bind(JpaPropertiesProvider.class).asEagerSingleton(); + bind(DataSourceProvider.class).asEagerSingleton(); + bind(DatabaseMigrationService.class).asEagerSingleton(); + + // Eagerly run Liquibase migrations on startup + bind(LiquibaseBootstrap.class).asEagerSingleton(); + } - // Eagerly run Flyway migrations on startup - bind(FlywayBootstrap.class).asEagerSingleton(); + @Provides + @Singleton + DataSource provideDataSource(DataSourceProvider dataSourceProvider) { + return dataSourceProvider.createDataSource(); } @Provides @@ -95,45 +104,11 @@ EntityManagerFactory provideEmf(JpaPropertiesProvider jpaPropertiesProvider) { return syncThreadForServiceLoader(() -> Persistence.createEntityManagerFactory("plotsquaredPU", props)); } - @Provides EntityManager provideEm(EntityManagerFactory emf) { return emf.createEntityManager(); } - @Provides - @Singleton - Flyway provideFlyway() { - String url; - String user = null; - String pass = null; - if (Storage.MySQL.USE) { - url = "jdbc:mysql://" + Storage.MySQL.HOST + ":" + Storage.MySQL.PORT + "/" + Storage.MySQL.DATABASE - + "?" + String.join("&", Storage.MySQL.PROPERTIES); - user = Storage.MySQL.USER; - pass = Storage.MySQL.PASSWORD; - } else { - url = "jdbc:sqlite:" + Storage.SQLite.DB + ".db"; - } - // Support prefixed table names in SQL migrations via placeholders - Map placeholders = new java.util.HashMap<>(); - placeholders.put("prefix", Storage.PREFIX == null ? "" : Storage.PREFIX); - - return Flyway.configure() - .dataSource(url, user, pass) - .locations("classpath:db/migration") - // Baseline an existing, unversioned schema to avoid destructive changes - .baselineOnMigrate(true) - .baselineVersion("0") - .baselineDescription("Baseline before migrating to JPA-managed schema") - // Prevent accidental data loss - .cleanDisabled(true) - // Enable ${prefix} usage in SQL files for table names - .placeholderReplacement(true) - .placeholders(placeholders) - .load(); - } - private T syncThreadForServiceLoader(Supplier supplier) { Thread currentThread = Thread.currentThread(); ClassLoader originalClassLoader = currentThread.getContextClassLoader(); From 59dd673dca66414933a25296938fe8f65f0c8d23 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 15:12:25 +0200 Subject: [PATCH 082/141] feat: add Liquibase changelogs for v8 migration and new installations --- .../db/changelog/db.changelog-master.xml | 17 + .../db/changelog/v7-to-v8-migration.xml | 282 ++++++++++++ .../changelog/v8.0.0/db.changelog-v8.0.0.xml | 419 ++++++++++++++++++ 3 files changed, 718 insertions(+) create mode 100644 Core/src/main/resources/db/changelog/db.changelog-master.xml create mode 100644 Core/src/main/resources/db/changelog/v7-to-v8-migration.xml create mode 100644 Core/src/main/resources/db/changelog/v8.0.0/db.changelog-v8.0.0.xml diff --git a/Core/src/main/resources/db/changelog/db.changelog-master.xml b/Core/src/main/resources/db/changelog/db.changelog-master.xml new file mode 100644 index 0000000000..7bfdf6cb3d --- /dev/null +++ b/Core/src/main/resources/db/changelog/db.changelog-master.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + diff --git a/Core/src/main/resources/db/changelog/v7-to-v8-migration.xml b/Core/src/main/resources/db/changelog/v7-to-v8-migration.xml new file mode 100644 index 0000000000..779fc8345f --- /dev/null +++ b/Core/src/main/resources/db/changelog/v7-to-v8-migration.xml @@ -0,0 +1,282 @@ + + + + + + + + + + + + Add auto-increment ID column to existing v7 plot table + + + + + + + + + + + + + + + + + + + + + + + Create plot_settings table for v8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Update plot_trusted foreign key to use new plot.id + + + + + + + + + + + + + + Update plot_helpers foreign key to use new plot.id + + + + + + + + + + + + Update plot_denied foreign key to use new plot.id + + + + + + + + + + + + Update plot_rating foreign key to use new plot.id + + + + + + + + + + + + + + + Add auto-increment ID column to existing v7 cluster table + + + + + + + + + + + + + + + + + Update cluster_helpers foreign key to use new cluster.id + + + + + + + + + + + + Update cluster_invited foreign key to use new cluster.id + + + + + + + + + + + + Update cluster_settings foreign key to use new cluster.id + + + + + + + + + + + + + + + Add auto-increment meta_id column to existing v7 player_meta table + + + + + + + + + + + + + + + + + + Create plot_flags table if missing + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/main/resources/db/changelog/v8.0.0/db.changelog-v8.0.0.xml b/Core/src/main/resources/db/changelog/v8.0.0/db.changelog-v8.0.0.xml new file mode 100644 index 0000000000..61d09110e5 --- /dev/null +++ b/Core/src/main/resources/db/changelog/v8.0.0/db.changelog-v8.0.0.xml @@ -0,0 +1,419 @@ + + + + + + + + + + + Create plot table for new v8 installations + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create plot_settings table for new v8 installations + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create plot_flags table for new v8 installations + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create plot membership tables for new v8 installations + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create plot comments and ratings tables for new v8 installations + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create player_meta table for new v8 installations + + + + + + + + + + + + + + + + + + + + + + + + + + + Create cluster tables for new v8 installations + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From bc55bafc52dbbe9aa0aa0c85d99efd668081cf17 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 15:12:34 +0200 Subject: [PATCH 083/141] feat: add DatabaseCommand for migrating databases between SQLite and MySQL, and from v7 to v8 format --- .../core/command/DatabaseCommand.java | 198 ++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/command/DatabaseCommand.java diff --git a/Core/src/main/java/com/plotsquared/core/command/DatabaseCommand.java b/Core/src/main/java/com/plotsquared/core/command/DatabaseCommand.java new file mode 100644 index 0000000000..60d55333a2 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/command/DatabaseCommand.java @@ -0,0 +1,198 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.command; + +import com.google.inject.Inject; +import com.plotsquared.core.configuration.Storage; +import com.plotsquared.core.configuration.caption.TranslatableCaption; +import com.plotsquared.core.persistence.config.DatabaseMigrationService; +import com.plotsquared.core.persistence.config.DataSourceProvider; +import com.plotsquared.core.player.PlotPlayer; +import com.plotsquared.core.util.task.RunnableVal; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.util.concurrent.CompletableFuture; + +/** + * Command for migrating databases between SQLite and MySQL, and from v7 to v8 format. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +@CommandDeclaration( + command = "database", + aliases = {"db", "migrate"}, + category = CommandCategory.ADMINISTRATION, + requiredType = RequiredType.CONSOLE, + permission = "plots.admin.database" +) +public class DatabaseCommand extends SubCommand { + + private final DatabaseMigrationService migrationService; + private final DataSourceProvider dataSourceProvider; + + @Inject + public DatabaseCommand(DatabaseMigrationService migrationService, DataSourceProvider dataSourceProvider) { + this.migrationService = migrationService; + this.dataSourceProvider = dataSourceProvider; + } + + @Override + public boolean onCommand(PlotPlayer player, String[] args) { + if (args.length == 0) { + player.sendMessage(TranslatableCaption.of("database.usage")); + return false; + } + + String subCommand = args[0].toLowerCase(); + + switch (subCommand) { + case "migrate-to-mysql": + if (args.length < 5) { + player.sendMessage(TranslatableCaption.of("database.migrate_mysql_usage")); + return false; + } + migrateToMySQL(player, args[1], args[2], args[3], args[4]); + break; + + case "migrate-to-sqlite": + if (args.length < 2) { + player.sendMessage(TranslatableCaption.of("database.migrate_sqlite_usage")); + return false; + } + migrateToSQLite(player, args[1]); + break; + + case "migrate-from-v7": + migrateFromV7(player); + break; + + case "status": + showDatabaseStatus(player); + break; + + default: + player.sendMessage(TranslatableCaption.of("database.unknown_subcommand")); + return false; + } + + return true; + } + + private void migrateToMySQL(PlotPlayer player, String host, String port, String database, String username) { + player.sendMessage(TranslatableCaption.of("database.migration_started")); + + CompletableFuture.runAsync(() -> { + try { + // Create target MySQL DataSource + String mysqlUrl = "jdbc:mysql://" + host + ":" + port + "/" + database + "?useSSL=false&allowPublicKeyRetrieval=true"; + DataSource targetDataSource = dataSourceProvider.createDataSource(mysqlUrl, username, + System.getProperty("mysql.password", ""), "com.mysql.cj.jdbc.Driver"); + + // Get current SQLite DataSource + DataSource sourceDataSource = dataSourceProvider.createDataSource(); + + try (Connection sourceConn = sourceDataSource.getConnection(); + Connection targetConn = targetDataSource.getConnection()) { + + migrationService.migrateBetweenDatabaseTypes(sourceConn, targetConn); + + player.sendMessage(TranslatableCaption.of("database.migration_completed")); + } + + } catch (Exception e) { + player.sendMessage(TranslatableCaption.of("database.migration_failed")); + e.printStackTrace(); + } + }); + } + + private void migrateToSQLite(PlotPlayer player, String sqliteFile) { + player.sendMessage(TranslatableCaption.of("database.migration_started")); + + CompletableFuture.runAsync(() -> { + try { + // Create target SQLite DataSource + String sqliteUrl = "jdbc:sqlite:" + sqliteFile + ".db"; + DataSource targetDataSource = dataSourceProvider.createDataSource(sqliteUrl, null, null, "org.sqlite.JDBC"); + + // Get current MySQL DataSource + DataSource sourceDataSource = dataSourceProvider.createDataSource(); + + try (Connection sourceConn = sourceDataSource.getConnection(); + Connection targetConn = targetDataSource.getConnection()) { + + migrationService.migrateBetweenDatabaseTypes(sourceConn, targetConn); + + player.sendMessage(TranslatableCaption.of("database.migration_completed")); + } + + } catch (Exception e) { + player.sendMessage(TranslatableCaption.of("database.migration_failed")); + e.printStackTrace(); + } + }); + } + + private void migrateFromV7(PlotPlayer player) { + player.sendMessage(TranslatableCaption.of("database.v7_migration_started")); + + CompletableFuture.runAsync(() -> { + try { + DataSource dataSource = dataSourceProvider.createDataSource(); + + try (Connection connection = dataSource.getConnection()) { + if (migrationService.isV7Database(connection)) { + migrationService.migrateFromV7(connection); + player.sendMessage(TranslatableCaption.of("database.v7_migration_completed")); + } else { + player.sendMessage(TranslatableCaption.of("database.not_v7_database")); + } + } + + } catch (Exception e) { + player.sendMessage(TranslatableCaption.of("database.v7_migration_failed")); + e.printStackTrace(); + } + }); + } + + private void showDatabaseStatus(PlotPlayer player) { + try { + DataSource dataSource = dataSourceProvider.createDataSource(); + + try (Connection connection = dataSource.getConnection()) { + String databaseType = Storage.MySQL.USE ? "MySQL" : "SQLite"; + boolean isV7 = migrationService.isV7Database(connection); + + player.sendMessage(TranslatableCaption.of("database.status_header")); + player.sendMessage(TranslatableCaption.of("database.status_type", databaseType)); + player.sendMessage(TranslatableCaption.of("database.status_version", isV7 ? "v7" : "v8")); + player.sendMessage(TranslatableCaption.of("database.status_prefix", Storage.PREFIX == null ? "none" : Storage.PREFIX)); + } + + } catch (Exception e) { + player.sendMessage(TranslatableCaption.of("database.status_error")); + e.printStackTrace(); + } + } +} From f6df7e2279e261207dc13a44a6a46aa9c61c5f02 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 15:39:13 +0200 Subject: [PATCH 084/141] feat: refactor DatabaseCommand and DatabaseMigrationService for Liquibase integration and enhance migration commands --- .../core/command/DatabaseCommand.java | 120 +++---- .../config/DatabaseMigrationService.java | 129 ++------ ...iquibaseCrossDatabaseMigrationService.java | 303 ++++++++++++++++++ .../persistence/config/PersistenceModule.java | 1 + 4 files changed, 390 insertions(+), 163 deletions(-) create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseCrossDatabaseMigrationService.java diff --git a/Core/src/main/java/com/plotsquared/core/command/DatabaseCommand.java b/Core/src/main/java/com/plotsquared/core/command/DatabaseCommand.java index 60d55333a2..f64982914b 100644 --- a/Core/src/main/java/com/plotsquared/core/command/DatabaseCommand.java +++ b/Core/src/main/java/com/plotsquared/core/command/DatabaseCommand.java @@ -23,15 +23,16 @@ import com.plotsquared.core.configuration.caption.TranslatableCaption; import com.plotsquared.core.persistence.config.DatabaseMigrationService; import com.plotsquared.core.persistence.config.DataSourceProvider; +import com.plotsquared.core.persistence.config.LiquibaseCrossDatabaseMigrationService; import com.plotsquared.core.player.PlotPlayer; -import com.plotsquared.core.util.task.RunnableVal; import javax.sql.DataSource; import java.sql.Connection; import java.util.concurrent.CompletableFuture; /** - * Command for migrating databases between SQLite and MySQL, and from v7 to v8 format. + * Command for migrating databases between SQLite and MySQL using Liquibase. + * All migrations now run completely through Liquibase without native SQL queries. * * @since 8.0.0 * @version 1.0.0 @@ -49,11 +50,15 @@ public class DatabaseCommand extends SubCommand { private final DatabaseMigrationService migrationService; private final DataSourceProvider dataSourceProvider; + private final LiquibaseCrossDatabaseMigrationService liquibaseMigrationService; @Inject - public DatabaseCommand(DatabaseMigrationService migrationService, DataSourceProvider dataSourceProvider) { + public DatabaseCommand(DatabaseMigrationService migrationService, + DataSourceProvider dataSourceProvider, + LiquibaseCrossDatabaseMigrationService liquibaseMigrationService) { this.migrationService = migrationService; this.dataSourceProvider = dataSourceProvider; + this.liquibaseMigrationService = liquibaseMigrationService; } @Override @@ -67,58 +72,50 @@ public boolean onCommand(PlotPlayer player, String[] args) { switch (subCommand) { case "migrate-to-mysql": - if (args.length < 5) { - player.sendMessage(TranslatableCaption.of("database.migrate_mysql_usage")); - return false; - } - migrateToMySQL(player, args[1], args[2], args[3], args[4]); + migrateToMySQL(player); break; case "migrate-to-sqlite": + migrateToSQLite(player); + break; + + case "backup": if (args.length < 2) { - player.sendMessage(TranslatableCaption.of("database.migrate_sqlite_usage")); + player.sendMessage(TranslatableCaption.of("database.backup_usage")); return false; } - migrateToSQLite(player, args[1]); - break; - - case "migrate-from-v7": - migrateFromV7(player); + createBackup(player, args[1]); break; case "status": showDatabaseStatus(player); break; + case "stats": + showDatabaseStats(player); + break; + default: player.sendMessage(TranslatableCaption.of("database.unknown_subcommand")); + player.sendMessage(TranslatableCaption.of("database.available_commands")); return false; } return true; } - private void migrateToMySQL(PlotPlayer player, String host, String port, String database, String username) { - player.sendMessage(TranslatableCaption.of("database.migration_started")); + private void migrateToMySQL(PlotPlayer player) { + player.sendMessage(TranslatableCaption.of("database.migration_mysql_started")); CompletableFuture.runAsync(() -> { try { - // Create target MySQL DataSource - String mysqlUrl = "jdbc:mysql://" + host + ":" + port + "/" + database + "?useSSL=false&allowPublicKeyRetrieval=true"; - DataSource targetDataSource = dataSourceProvider.createDataSource(mysqlUrl, username, - System.getProperty("mysql.password", ""), "com.mysql.cj.jdbc.Driver"); + liquibaseMigrationService.migrateToMySQL(); - // Get current SQLite DataSource - DataSource sourceDataSource = dataSourceProvider.createDataSource(); - - try (Connection sourceConn = sourceDataSource.getConnection(); - Connection targetConn = targetDataSource.getConnection()) { - - migrationService.migrateBetweenDatabaseTypes(sourceConn, targetConn); - - player.sendMessage(TranslatableCaption.of("database.migration_completed")); - } + player.sendMessage(TranslatableCaption.of("database.migration_completed")); + player.sendMessage(TranslatableCaption.of("database.update_config_reminder")); + } catch (IllegalStateException e) { + player.sendMessage(TranslatableCaption.of("database.mysql_not_configured")); } catch (Exception e) { player.sendMessage(TranslatableCaption.of("database.migration_failed")); e.printStackTrace(); @@ -126,26 +123,18 @@ private void migrateToMySQL(PlotPlayer player, String host, String port, Stri }); } - private void migrateToSQLite(PlotPlayer player, String sqliteFile) { - player.sendMessage(TranslatableCaption.of("database.migration_started")); + private void migrateToSQLite(PlotPlayer player) { + player.sendMessage(TranslatableCaption.of("database.migration_sqlite_started")); CompletableFuture.runAsync(() -> { try { - // Create target SQLite DataSource - String sqliteUrl = "jdbc:sqlite:" + sqliteFile + ".db"; - DataSource targetDataSource = dataSourceProvider.createDataSource(sqliteUrl, null, null, "org.sqlite.JDBC"); + liquibaseMigrationService.migrateToSQLite(); - // Get current MySQL DataSource - DataSource sourceDataSource = dataSourceProvider.createDataSource(); - - try (Connection sourceConn = sourceDataSource.getConnection(); - Connection targetConn = targetDataSource.getConnection()) { - - migrationService.migrateBetweenDatabaseTypes(sourceConn, targetConn); - - player.sendMessage(TranslatableCaption.of("database.migration_completed")); - } + player.sendMessage(TranslatableCaption.of("database.migration_completed")); + player.sendMessage(TranslatableCaption.of("database.update_config_reminder")); + } catch (IllegalStateException e) { + player.sendMessage(TranslatableCaption.of("database.sqlite_not_configured")); } catch (Exception e) { player.sendMessage(TranslatableCaption.of("database.migration_failed")); e.printStackTrace(); @@ -153,24 +142,17 @@ private void migrateToSQLite(PlotPlayer player, String sqliteFile) { }); } - private void migrateFromV7(PlotPlayer player) { - player.sendMessage(TranslatableCaption.of("database.v7_migration_started")); + private void createBackup(PlotPlayer player, String backupSuffix) { + player.sendMessage(TranslatableCaption.of("database.backup_started")); CompletableFuture.runAsync(() -> { try { - DataSource dataSource = dataSourceProvider.createDataSource(); - - try (Connection connection = dataSource.getConnection()) { - if (migrationService.isV7Database(connection)) { - migrationService.migrateFromV7(connection); - player.sendMessage(TranslatableCaption.of("database.v7_migration_completed")); - } else { - player.sendMessage(TranslatableCaption.of("database.not_v7_database")); - } - } + liquibaseMigrationService.migrateToBackupDatabase(backupSuffix); + + player.sendMessage(TranslatableCaption.of("database.backup_completed")); } catch (Exception e) { - player.sendMessage(TranslatableCaption.of("database.v7_migration_failed")); + player.sendMessage(TranslatableCaption.of("database.backup_failed")); e.printStackTrace(); } }); @@ -182,11 +164,11 @@ private void showDatabaseStatus(PlotPlayer player) { try (Connection connection = dataSource.getConnection()) { String databaseType = Storage.MySQL.USE ? "MySQL" : "SQLite"; - boolean isV7 = migrationService.isV7Database(connection); + String version = migrationService.getDatabaseVersion(connection); player.sendMessage(TranslatableCaption.of("database.status_header")); player.sendMessage(TranslatableCaption.of("database.status_type", databaseType)); - player.sendMessage(TranslatableCaption.of("database.status_version", isV7 ? "v7" : "v8")); + player.sendMessage(TranslatableCaption.of("database.status_version", version)); player.sendMessage(TranslatableCaption.of("database.status_prefix", Storage.PREFIX == null ? "none" : Storage.PREFIX)); } @@ -195,4 +177,22 @@ private void showDatabaseStatus(PlotPlayer player) { e.printStackTrace(); } } + + private void showDatabaseStats(PlotPlayer player) { + try { + DataSource dataSource = dataSourceProvider.createDataSource(); + + try (Connection connection = dataSource.getConnection()) { + String stats = migrationService.getDatabaseStatistics(connection); + + for (String line : stats.split("\n")) { + player.sendMessage(TranslatableCaption.of("database.stats_line", line)); + } + } + + } catch (Exception e) { + player.sendMessage(TranslatableCaption.of("database.stats_error")); + e.printStackTrace(); + } + } } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/DatabaseMigrationService.java b/Core/src/main/java/com/plotsquared/core/persistence/config/DatabaseMigrationService.java index ae27cd631d..59bbf75e92 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/DatabaseMigrationService.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/DatabaseMigrationService.java @@ -23,19 +23,13 @@ import java.sql.Connection; import java.sql.DatabaseMetaData; -import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.List; import java.util.logging.Logger; /** - * Service for handling database migrations between different PlotSquared versions - * and database systems (SQLite <-> MySQL). - * - * Note: v7 to v8 migration is now handled completely by Liquibase changesets. + * Service for providing database information and status. + * All database migrations are now handled completely by Liquibase. * * @since 8.0.0 * @version 1.0.0 @@ -48,7 +42,7 @@ public final class DatabaseMigrationService { /** * Checks if the current database is using the v7 schema format. - * This is now mainly used for informational purposes since Liquibase handles the migration. + * This is used for informational purposes since Liquibase handles the migration automatically. */ public boolean isV7Database(Connection connection) throws SQLException { String prefix = Storage.PREFIX == null ? "" : Storage.PREFIX; @@ -101,111 +95,40 @@ public String getDatabaseVersion(Connection connection) throws SQLException { } /** - * Migrates data from one database type to another (e.g., SQLite to MySQL). - * This is the main functionality remaining in this service since schema migration - * is now handled by Liquibase. + * Gets database statistics for informational purposes. */ - public void migrateBetweenDatabaseTypes(Connection sourceConnection, Connection targetConnection) throws SQLException { - LOGGER.info("Starting cross-database migration..."); + public String getDatabaseStatistics(Connection connection) throws SQLException { + String prefix = Storage.PREFIX == null ? "" : Storage.PREFIX; + StringBuilder stats = new StringBuilder(); try { - targetConnection.setAutoCommit(false); - - String prefix = Storage.PREFIX == null ? "" : Storage.PREFIX; - - // Get all tables from source database - List tablesToMigrate = getExistingTables(sourceConnection, prefix); - - for (String tableName : tablesToMigrate) { - migrateTable(sourceConnection, targetConnection, tableName); - } - - targetConnection.commit(); - LOGGER.info("Cross-database migration completed successfully."); - - } catch (SQLException e) { - targetConnection.rollback(); - LOGGER.severe("Cross-database migration failed: " + e.getMessage()); - throw e; - } finally { - targetConnection.setAutoCommit(true); - } - } + stats.append("Database Statistics:\n"); + stats.append("- Version: ").append(getDatabaseVersion(connection)).append("\n"); + stats.append("- Prefix: ").append(prefix.isEmpty() ? "none" : prefix).append("\n"); - private List getExistingTables(Connection connection, String prefix) throws SQLException { - List tables = new ArrayList<>(); - DatabaseMetaData metaData = connection.getMetaData(); - - try (ResultSet rs = metaData.getTables(null, null, prefix + "%", new String[]{"TABLE"})) { - while (rs.next()) { - String tableName = rs.getString("TABLE_NAME"); - // Skip backup and temporary tables, and Liquibase tables - if (!tableName.contains("_backup_") && !tableName.contains("_v7_temp") && - !tableName.contains("DATABASECHANGELOG")) { - tables.add(tableName); + // Count plots if table exists + try (ResultSet tables = connection.getMetaData().getTables(null, null, prefix + "plot", new String[]{"TABLE"})) { + if (tables.next()) { + try (var stmt = connection.createStatement(); + var rs = stmt.executeQuery("SELECT COUNT(*) FROM " + prefix + "plot")) { + if (rs.next()) { + stats.append("- Total plots: ").append(rs.getInt(1)).append("\n"); + } + } } } - } - - return tables; - } - private void migrateTable(Connection source, Connection target, String tableName) throws SQLException { - LOGGER.info("Migrating table: " + tableName); - - // First, clear the target table - try (Statement stmt = target.createStatement()) { - stmt.execute("DELETE FROM " + tableName); + } catch (SQLException e) { + stats.append("- Error retrieving statistics: ").append(e.getMessage()); } - // Get all data from source table - try (Statement sourceStmt = source.createStatement(); - ResultSet rs = sourceStmt.executeQuery("SELECT * FROM " + tableName)) { - - if (!rs.next()) { - LOGGER.info("Table " + tableName + " is empty, skipping"); - return; - } - - // Get column metadata - int columnCount = rs.getMetaData().getColumnCount(); - List columnNames = new ArrayList<>(); - for (int i = 1; i <= columnCount; i++) { - columnNames.add(rs.getMetaData().getColumnName(i)); - } - - // Build insert statement - StringBuilder insertQuery = new StringBuilder("INSERT INTO " + tableName + " ("); - insertQuery.append(String.join(", ", columnNames)); - insertQuery.append(") VALUES ("); - for (int i = 0; i < columnCount; i++) { - if (i > 0) insertQuery.append(", "); - insertQuery.append("?"); - } - insertQuery.append(")"); - - try (PreparedStatement insertStmt = target.prepareStatement(insertQuery.toString())) { - rs.beforeFirst(); - - int count = 0; - while (rs.next()) { - for (int i = 1; i <= columnCount; i++) { - insertStmt.setObject(i, rs.getObject(i)); - } - insertStmt.addBatch(); - - if (++count % 1000 == 0) { - insertStmt.executeBatch(); - } - } - - insertStmt.executeBatch(); - LOGGER.info("Migrated " + count + " rows from table " + tableName); - } - } + return stats.toString(); } - private boolean tableExists(Connection connection, String tableName) throws SQLException { + /** + * Checks if a table exists in the database. + */ + public boolean tableExists(Connection connection, String tableName) throws SQLException { DatabaseMetaData metaData = connection.getMetaData(); try (ResultSet tables = metaData.getTables(null, null, tableName, new String[]{"TABLE"})) { return tables.next(); diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseCrossDatabaseMigrationService.java b/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseCrossDatabaseMigrationService.java new file mode 100644 index 0000000000..ec732bbdc4 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseCrossDatabaseMigrationService.java @@ -0,0 +1,303 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.config; + +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.plotsquared.core.configuration.Storage; +import liquibase.Liquibase; +import liquibase.database.Database; +import liquibase.database.DatabaseFactory; +import liquibase.database.jvm.JdbcConnection; +import liquibase.diff.DiffGeneratorFactory; +import liquibase.diff.DiffResult; +import liquibase.diff.compare.CompareControl; +import liquibase.diff.output.DiffOutputControl; +import liquibase.diff.output.changelog.DiffToChangeLog; +import liquibase.resource.ClassLoaderResourceAccessor; +import liquibase.snapshot.DatabaseSnapshot; + +import javax.sql.DataSource; +import java.io.PrintStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.sql.Connection; +import java.util.logging.Logger; + +/** + * Service for handling cross-database migrations using pure Liquibase functionality. + * Uses Liquibase's native generateChangeLog and diffChangeLog capabilities. + * + * @since 8.0.0 + * @version 2.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +@Singleton +public final class LiquibaseCrossDatabaseMigrationService { + private static final Logger LOGGER = Logger.getLogger(LiquibaseCrossDatabaseMigrationService.class.getName()); + + private final DataSourceProvider dataSourceProvider; + + @Inject + public LiquibaseCrossDatabaseMigrationService(DataSourceProvider dataSourceProvider) { + this.dataSourceProvider = dataSourceProvider; + } + + /** + * Migrates from current database to MySQL using Liquibase's native capabilities. + */ + public void migrateToMySQL() { + LOGGER.info("Starting pure Liquibase migration to MySQL..."); + + if (!Storage.MySQL.USE) { + throw new IllegalStateException("MySQL is not configured. Please configure MySQL settings in the config file first."); + } + + try { + // Create MySQL datasource using config settings + String mysqlUrl = "jdbc:mysql://" + Storage.MySQL.HOST + ":" + Storage.MySQL.PORT + "/" + Storage.MySQL.DATABASE + + "?" + String.join("&", Storage.MySQL.PROPERTIES) + "&createDatabaseIfNotExist=true"; + DataSource targetDataSource = dataSourceProvider.createDataSource(mysqlUrl, Storage.MySQL.USER, Storage.MySQL.PASSWORD, "com.mysql.cj.jdbc.Driver"); + + // Get current datasource + DataSource sourceDataSource = dataSourceProvider.createDataSource(); + + // Perform migration using pure Liquibase + migrateUsingLiquibaseNative(sourceDataSource, targetDataSource); + + LOGGER.info("Migration to MySQL completed successfully."); + + } catch (Exception e) { + LOGGER.severe("Migration to MySQL failed: " + e.getMessage()); + e.printStackTrace(); + throw new RuntimeException("Migration to MySQL failed", e); + } + } + + /** + * Migrates from current database to SQLite using Liquibase's native capabilities. + */ + public void migrateToSQLite() { + LOGGER.info("Starting pure Liquibase migration to SQLite..."); + + if (!Storage.SQLite.USE) { + throw new IllegalStateException("SQLite is not configured. Please configure SQLite settings in the config file first."); + } + + try { + // Create SQLite datasource using config settings + String sqliteUrl = "jdbc:sqlite:" + Storage.SQLite.DB + ".db"; + DataSource targetDataSource = dataSourceProvider.createDataSource(sqliteUrl, null, null, "org.sqlite.JDBC"); + + // Get current datasource + DataSource sourceDataSource = dataSourceProvider.createDataSource(); + + // Perform migration using pure Liquibase + migrateUsingLiquibaseNative(sourceDataSource, targetDataSource); + + LOGGER.info("Migration to SQLite completed successfully."); + + } catch (Exception e) { + LOGGER.severe("Migration to SQLite failed: " + e.getMessage()); + e.printStackTrace(); + throw new RuntimeException("Migration to SQLite failed", e); + } + } + + /** + * Migrates from current database to a backup database. + */ + public void migrateToBackupDatabase(String backupSuffix) { + LOGGER.info("Starting migration to backup database with suffix: " + backupSuffix); + + try { + DataSource sourceDataSource = dataSourceProvider.createDataSource(); + DataSource targetDataSource; + + if (Storage.MySQL.USE) { + // Create backup MySQL database + String backupDatabase = Storage.MySQL.DATABASE + "_" + backupSuffix; + String mysqlUrl = "jdbc:mysql://" + Storage.MySQL.HOST + ":" + Storage.MySQL.PORT + "/" + backupDatabase + + "?" + String.join("&", Storage.MySQL.PROPERTIES) + "&createDatabaseIfNotExist=true"; + targetDataSource = dataSourceProvider.createDataSource(mysqlUrl, Storage.MySQL.USER, Storage.MySQL.PASSWORD, "com.mysql.cj.jdbc.Driver"); + } else { + // Create backup SQLite database + String backupFile = Storage.SQLite.DB + "_" + backupSuffix; + String sqliteUrl = "jdbc:sqlite:" + backupFile + ".db"; + targetDataSource = dataSourceProvider.createDataSource(sqliteUrl, null, null, "org.sqlite.JDBC"); + } + + // Perform migration using pure Liquibase + migrateUsingLiquibaseNative(sourceDataSource, targetDataSource); + + LOGGER.info("Migration to backup database completed successfully."); + + } catch (Exception e) { + LOGGER.severe("Migration to backup database failed: " + e.getMessage()); + e.printStackTrace(); + throw new RuntimeException("Migration to backup database failed", e); + } + } + + /** + * Performs the actual migration using Liquibase's native generateChangeLog functionality. + * This approach eliminates the need for CSV export/import and uses pure Liquibase operations. + */ + private void migrateUsingLiquibaseNative(DataSource sourceDataSource, DataSource targetDataSource) throws Exception { + // Create temporary file for the generated changelog + Path tempChangelog = Files.createTempFile("plotsquared-migration-", ".xml"); + + try (Connection sourceConnection = sourceDataSource.getConnection(); + Connection targetConnection = targetDataSource.getConnection()) { + + Database sourceDatabase = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(sourceConnection)); + Database targetDatabase = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(targetConnection)); + + // Step 1: Create the target schema structure first + LOGGER.info("Creating target database schema..."); + Liquibase schemaLiquibase = new Liquibase("db/changelog/db.changelog-master.xml", + new ClassLoaderResourceAccessor(), targetDatabase); + schemaLiquibase.update(""); + + // Step 2: Generate changelog with data from source database + LOGGER.info("Generating changelog with data from source database..."); + generateDataChangeLog(sourceDatabase, tempChangelog); + + // Step 3: Apply the data changelog to target database + LOGGER.info("Applying data to target database..."); + Liquibase dataLiquibase = new Liquibase(tempChangelog.toString(), + new ClassLoaderResourceAccessor(), targetDatabase); + dataLiquibase.update(""); + + LOGGER.info("Pure Liquibase migration completed successfully."); + + } finally { + // Cleanup temporary file + try { + Files.deleteIfExists(tempChangelog); + } catch (Exception e) { + LOGGER.warning("Could not delete temporary changelog file: " + e.getMessage()); + } + } + } + + /** + * Generates a Liquibase changelog with data using Liquibase's native capabilities. + */ + private void generateDataChangeLog(Database sourceDatabase, Path outputFile) throws Exception { + try (PrintStream output = new PrintStream(Files.newOutputStream(outputFile))) { + + // Create Liquibase instance + Liquibase liquibase = new Liquibase("", new ClassLoaderResourceAccessor(), sourceDatabase); + + // Generate changelog including data + // This uses Liquibase's built-in generateChangeLog with data option + generateChangeLogUsingDiff(sourceDatabase, sourceDatabase, outputFile);// import liquibase.snapshot.DatabaseSnapshot; // Entfernen + // import liquibase.structure.DatabaseSnapshot; // Entfernen + + } catch (Exception e) { + LOGGER.severe("Failed to generate data changelog: " + e.getMessage()); + throw e; + } + } + + /** + * Alternative approach using Liquibase's diff functionality for more control. + */ + private void generateChangeLogUsingDiff(Database sourceDatabase, Database targetDatabase, Path outputFile) throws Exception { + try (PrintStream output = new PrintStream(Files.newOutputStream(outputFile))) { + + // Create database snapshots + DatabaseSnapshot sourceSnapshot = liquibase.snapshot.SnapshotGeneratorFactory.getInstance() + .createSnapshot(sourceDatabase.getDefaultSchema(), sourceDatabase, new liquibase.snapshot.SnapshotControl(sourceDatabase)); + + DatabaseSnapshot targetSnapshot = liquibase.snapshot.SnapshotGeneratorFactory.getInstance() + .createSnapshot(targetDatabase.getDefaultSchema(), targetDatabase, new liquibase.snapshot.SnapshotControl(targetDatabase)); + + // Compare databases + DiffResult diffResult = DiffGeneratorFactory.getInstance().compare(sourceSnapshot, targetSnapshot, new CompareControl()); + + // Generate changelog from diff + DiffToChangeLog changeLogWriter = new DiffToChangeLog(diffResult, new DiffOutputControl(true, true, true, null)); + changeLogWriter.print(output); + + } catch (Exception e) { + LOGGER.severe("Failed to generate changelog using diff: " + e.getMessage()); + throw e; + } + } + + /** + * Validates that the migration was successful by comparing database structures. + */ + public boolean validateMigration(DataSource sourceDataSource, DataSource targetDataSource) { + try (Connection sourceConnection = sourceDataSource.getConnection(); + Connection targetConnection = targetDataSource.getConnection()) { + + Database sourceDatabase = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(sourceConnection)); + Database targetDatabase = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(targetConnection)); + + // Create snapshots of both databases + DatabaseSnapshot sourceSnapshot = liquibase.snapshot.SnapshotGeneratorFactory.getInstance() + .createSnapshot(sourceDatabase.getDefaultSchema(), sourceDatabase, new liquibase.snapshot.SnapshotControl(sourceDatabase)); + + DatabaseSnapshot targetSnapshot = liquibase.snapshot.SnapshotGeneratorFactory.getInstance() + .createSnapshot(targetDatabase.getDefaultSchema(), targetDatabase, new liquibase.snapshot.SnapshotControl(targetDatabase)); + + // Compare structure and data + DiffResult diffResult = DiffGeneratorFactory.getInstance().compare(sourceSnapshot, targetSnapshot, new CompareControl()); + + boolean hasUnexpectedDiffs = !diffResult.areEqual(); + + if (!hasUnexpectedDiffs) { + LOGGER.info("Migration validation successful: Databases are identical"); + } else { + LOGGER.warning("Migration validation found differences between source and target databases"); + } + + return !hasUnexpectedDiffs; + + } catch (Exception e) { + LOGGER.severe("Error during migration validation: " + e.getMessage()); + return false; + } + } + + /** + * Gets migration statistics without hacky record counting. + */ + public String getMigrationInfo(DataSource dataSource) { + try (Connection connection = dataSource.getConnection()) { + Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection)); + + // Use Liquibase to get database info + StringBuilder info = new StringBuilder(); + info.append("Database Type: ").append(database.getDatabaseProductName()).append("\n"); + info.append("Database Version: ").append(database.getDatabaseProductVersion()).append("\n"); + info.append("Default Schema: ").append(database.getDefaultSchemaName()).append("\n"); + + return info.toString(); + + } catch (Exception e) { + LOGGER.warning("Error getting migration info: " + e.getMessage()); + return "Error retrieving database information"; + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java b/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java index eaea7ce343..a16d9afd9b 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java @@ -86,6 +86,7 @@ protected void configure() { bind(JpaPropertiesProvider.class).asEagerSingleton(); bind(DataSourceProvider.class).asEagerSingleton(); bind(DatabaseMigrationService.class).asEagerSingleton(); + bind(LiquibaseCrossDatabaseMigrationService.class).asEagerSingleton(); // Eagerly run Liquibase migrations on startup bind(LiquibaseBootstrap.class).asEagerSingleton(); From c69e7a043dd8f608b53fe01e7eb7d27febf6ebf0 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 16:02:04 +0200 Subject: [PATCH 085/141] feat: enhance Liquibase migration support for MySQL and SQLite with new changelogs and ID column handling --- .../config/LiquibaseBootstrap.java | 40 +- .../db/changelog/db.changelog-master.xml | 4 + .../db/changelog/v7-to-v8-migration.xml | 143 +++--- .../changelog/v7-to-v8-sqlite-migration.xml | 440 ++++++++++++++++++ 4 files changed, 558 insertions(+), 69 deletions(-) create mode 100644 Core/src/main/resources/db/changelog/v7-to-v8-sqlite-migration.xml diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseBootstrap.java b/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseBootstrap.java index fc601eebe9..8ce087e33b 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseBootstrap.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseBootstrap.java @@ -44,23 +44,37 @@ public final class LiquibaseBootstrap { @Inject public LiquibaseBootstrap(DataSource dataSource, DatabaseMigrationService migrationService) { - try (Connection connection = dataSource.getConnection()) { - Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection)); + syncThreadForServiceLoader(() -> { + try (Connection connection = dataSource.getConnection()) { + Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection)); - // Log database version information - String dbVersion = migrationService.getDatabaseVersion(connection); - LOGGER.info("Detected database version: " + dbVersion); + // Log database version information + String dbVersion = migrationService.getDatabaseVersion(connection); + LOGGER.info("Detected database version: " + dbVersion); - // Run Liquibase migrations - this will handle both v7->v8 migration and new v8 installations - Liquibase liquibase = new Liquibase("db/changelog/db.changelog-master.xml", - new ClassLoaderResourceAccessor(), database); + // Run Liquibase migrations - this will handle both v7->v8 migration and new v8 installations + Liquibase liquibase = new Liquibase("db/changelog/db.changelog-master.xml", + new ClassLoaderResourceAccessor(), database); - liquibase.update(""); - LOGGER.info("Liquibase migration completed successfully."); + liquibase.update(""); + LOGGER.info("Liquibase migration completed successfully."); - } catch (Exception e) { - LOGGER.severe("Liquibase migration failed: " + e.getMessage()); - throw new RuntimeException("Database migration failed", e); + } catch (Exception e) { + LOGGER.severe("Liquibase migration failed: " + e.getMessage()); + throw new RuntimeException("Database migration failed", e); + } + }); + } + + void syncThreadForServiceLoader(Runnable runnable) { + Thread currentThread = Thread.currentThread(); + ClassLoader originalClassLoader = currentThread.getContextClassLoader(); + ClassLoader pluginClassLoader = this.getClass().getClassLoader(); + try { + currentThread.setContextClassLoader(pluginClassLoader); + runnable.run(); + } finally { + currentThread.setContextClassLoader(originalClassLoader); } } } diff --git a/Core/src/main/resources/db/changelog/db.changelog-master.xml b/Core/src/main/resources/db/changelog/db.changelog-master.xml index 7bfdf6cb3d..a2913cca32 100644 --- a/Core/src/main/resources/db/changelog/db.changelog-master.xml +++ b/Core/src/main/resources/db/changelog/db.changelog-master.xml @@ -6,8 +6,12 @@ http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.20.xsd"> + + + + diff --git a/Core/src/main/resources/db/changelog/v7-to-v8-migration.xml b/Core/src/main/resources/db/changelog/v7-to-v8-migration.xml index 779fc8345f..8c12c6257d 100644 --- a/Core/src/main/resources/db/changelog/v7-to-v8-migration.xml +++ b/Core/src/main/resources/db/changelog/v7-to-v8-migration.xml @@ -5,40 +5,43 @@ xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.20.xsd"> - + - - - - + + + + + + + - Add auto-increment ID column to existing v7 plot table + Add auto-increment ID column to existing v7 plot table (MySQL) - - - - + - - - + + + + + + - Create plot_settings table for v8 + Create plot_settings table for v8 (MySQL) @@ -78,18 +81,19 @@ onDelete="CASCADE"/> - + - - + + + + + - Update plot_trusted foreign key to use new plot.id + Update plot_trusted foreign key to use new plot.id (MySQL) - - - - + + + + + - Update plot_helpers foreign key to use new plot.id + Update plot_helpers foreign key to use new plot.id (MySQL) @@ -117,10 +124,13 @@ - - + + + + + - Update plot_denied foreign key to use new plot.id + Update plot_denied foreign key to use new plot.id (MySQL) @@ -134,10 +144,13 @@ - - + + + + + - Update plot_rating foreign key to use new plot.id + Update plot_rating foreign key to use new plot.id (MySQL) @@ -149,15 +162,18 @@ onDelete="CASCADE"/> - + - - - - + + + + + + + - Add auto-increment ID column to existing v7 cluster table + Add auto-increment ID column to existing v7 cluster table (MySQL) @@ -168,13 +184,16 @@ - + - - + + + + + - Update cluster_helpers foreign key to use new cluster.id + Update cluster_helpers foreign key to use new cluster.id (MySQL) @@ -188,10 +207,13 @@ - - + + + + + - Update cluster_invited foreign key to use new cluster.id + Update cluster_invited foreign key to use new cluster.id (MySQL) @@ -205,10 +227,13 @@ - - + + + + + - Update cluster_settings foreign key to use new cluster.id + Update cluster_settings foreign key to use new cluster.id (MySQL) @@ -220,15 +245,18 @@ onDelete="CASCADE"/> - + - - - - + + + + + + + - Add auto-increment meta_id column to existing v7 player_meta table + Add auto-increment meta_id column to existing v7 player_meta table (MySQL) @@ -239,14 +267,17 @@ - + - - - + + + + + + - Create plot_flags table if missing + Create plot_flags table if missing (MySQL) diff --git a/Core/src/main/resources/db/changelog/v7-to-v8-sqlite-migration.xml b/Core/src/main/resources/db/changelog/v7-to-v8-sqlite-migration.xml new file mode 100644 index 0000000000..8b0321621c --- /dev/null +++ b/Core/src/main/resources/db/changelog/v7-to-v8-sqlite-migration.xml @@ -0,0 +1,440 @@ + + + + + + + + + + + + + + + Recreate plot table with ID column for SQLite v7 to v8 migration + + + + + + + + + + + + + + + + + + + + + + + + + + INSERT INTO ${prefix}plot_new (plot_id_x, plot_id_z, world, owner, timestamp) + SELECT plot_id_x, plot_id_z, world, owner, timestamp FROM ${prefix}plot + + + + + + + ALTER TABLE ${prefix}plot_new RENAME TO ${prefix}plot + + + + + + + + + + + + + + + + Create plot_settings table for SQLite v8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Update plot_trusted to use new plot IDs for SQLite + + + + + + + + + + + + + + INSERT INTO ${prefix}plot_trusted_new (plot_plot_id, user_uuid) + SELECT p.id, pt.user_uuid + FROM ${prefix}plot_trusted pt + JOIN ${prefix}plot p ON pt.plot_id_x = p.plot_id_x AND pt.plot_id_z = p.plot_id_z AND pt.world = p.world + + + + ALTER TABLE ${prefix}plot_trusted_new RENAME TO ${prefix}plot_trusted + + + + + + + + + + + + + Update plot_helpers to use new plot IDs for SQLite + + + + + + + + + + + + INSERT INTO ${prefix}plot_helpers_new (plot_plot_id, user_uuid) + SELECT p.id, ph.user_uuid + FROM ${prefix}plot_helpers ph + JOIN ${prefix}plot p ON ph.plot_id_x = p.plot_id_x AND ph.plot_id_z = p.plot_id_z AND ph.world = p.world + + + + ALTER TABLE ${prefix}plot_helpers_new RENAME TO ${prefix}plot_helpers + + + + + + + + + + + + + Update plot_denied to use new plot IDs for SQLite + + + + + + + + + + + + INSERT INTO ${prefix}plot_denied_new (plot_plot_id, user_uuid) + SELECT p.id, pd.user_uuid + FROM ${prefix}plot_denied pd + JOIN ${prefix}plot p ON pd.plot_id_x = p.plot_id_x AND pd.plot_id_z = p.plot_id_z AND pd.world = p.world + + + + ALTER TABLE ${prefix}plot_denied_new RENAME TO ${prefix}plot_denied + + + + + + + + + + + + + Update plot_rating to use new plot IDs for SQLite + + + + + + + + + + + + + + + INSERT INTO ${prefix}plot_rating_new (plot_plot_id, rating, player) + SELECT p.id, pr.rating, pr.player + FROM ${prefix}plot_rating pr + JOIN ${prefix}plot p ON pr.plot_id_x = p.plot_id_x AND pr.plot_id_z = p.plot_id_z AND pr.world = p.world + + + + ALTER TABLE ${prefix}plot_rating_new RENAME TO ${prefix}plot_rating + + + + + + + + + + + + + + + + + + Recreate cluster table with ID column for SQLite v7 to v8 migration + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + INSERT INTO ${prefix}cluster_new (pos1_x, pos1_z, pos2_x, pos2_z, owner, world, timestamp) + SELECT pos1_x, pos1_z, pos2_x, pos2_z, owner, world, timestamp FROM ${prefix}cluster + + + + ALTER TABLE ${prefix}cluster_new RENAME TO ${prefix}cluster + + + + + + + + + + + + Update cluster_helpers to use new cluster IDs for SQLite + + + + + + + + + + + + INSERT INTO ${prefix}cluster_helpers_new (cluster_id, user_uuid) + SELECT c.id, ch.user_uuid + FROM ${prefix}cluster_helpers ch + JOIN ${prefix}cluster c ON ch.cluster_id = c.id + + + + ALTER TABLE ${prefix}cluster_helpers_new RENAME TO ${prefix}cluster_helpers + + + + + + + + + + + + + + + + Add auto-increment meta_id column to existing v7 player_meta table (SQLite) + + + + + + + + + + + + + + + + + + INSERT INTO ${prefix}player_meta_new (uuid, key, value) + SELECT uuid, key, value FROM ${prefix}player_meta + + + + ALTER TABLE ${prefix}player_meta_new RENAME TO ${prefix}player_meta + + + + + + + + + + + + + + + Create plot_flags table if missing (SQLite) + + + + + + + + + + + + + + + + + + + + + + + + + + From cb49ac1a4a272c2763a6e06bcfdecc944559db22 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 16:13:50 +0200 Subject: [PATCH 086/141] feat: exclude SQLite from MySQL-specific migration changes in v7-to-v8 migration script --- .../db/changelog/v7-to-v8-migration.xml | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/Core/src/main/resources/db/changelog/v7-to-v8-migration.xml b/Core/src/main/resources/db/changelog/v7-to-v8-migration.xml index 8c12c6257d..45298bc526 100644 --- a/Core/src/main/resources/db/changelog/v7-to-v8-migration.xml +++ b/Core/src/main/resources/db/changelog/v7-to-v8-migration.xml @@ -15,6 +15,9 @@ + + + Add auto-increment ID column to existing v7 plot table (MySQL) @@ -40,6 +43,9 @@ + + + Create plot_settings table for v8 (MySQL) @@ -89,6 +95,9 @@ + + + Update plot_trusted foreign key to use new plot.id (MySQL) @@ -109,6 +118,9 @@ + + + Update plot_helpers foreign key to use new plot.id (MySQL) @@ -129,6 +141,9 @@ + + + Update plot_denied foreign key to use new plot.id (MySQL) @@ -149,6 +164,9 @@ + + + Update plot_rating foreign key to use new plot.id (MySQL) @@ -172,6 +190,9 @@ + + + Add auto-increment ID column to existing v7 cluster table (MySQL) @@ -192,6 +213,9 @@ + + + Update cluster_helpers foreign key to use new cluster.id (MySQL) @@ -212,6 +236,9 @@ + + + Update cluster_invited foreign key to use new cluster.id (MySQL) @@ -232,6 +259,9 @@ + + + Update cluster_settings foreign key to use new cluster.id (MySQL) @@ -255,6 +285,9 @@ + + + Add auto-increment meta_id column to existing v7 player_meta table (MySQL) @@ -276,6 +309,9 @@ + + + Create plot_flags table if missing (MySQL) From 2915b426a362b5da03c69a1bf9b29f36643bae60 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 16:36:03 +0200 Subject: [PATCH 087/141] feat: fix MySQL datasource URL construction to ensure database creation if it does not exist --- .../config/LiquibaseCrossDatabaseMigrationService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseCrossDatabaseMigrationService.java b/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseCrossDatabaseMigrationService.java index ec732bbdc4..397a9af0d3 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseCrossDatabaseMigrationService.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseCrossDatabaseMigrationService.java @@ -72,7 +72,7 @@ public void migrateToMySQL() { try { // Create MySQL datasource using config settings - String mysqlUrl = "jdbc:mysql://" + Storage.MySQL.HOST + ":" + Storage.MySQL.PORT + "/" + Storage.MySQL.DATABASE + + String mysqlUrl = "jdbc:mysql://" + Storage.MySQL.HOST + ":" + Storage.MySQL.PORT + "/" + Storage.MySQL.DATABASE + "?" + String.join("&", Storage.MySQL.PROPERTIES) + "&createDatabaseIfNotExist=true"; DataSource targetDataSource = dataSourceProvider.createDataSource(mysqlUrl, Storage.MySQL.USER, Storage.MySQL.PASSWORD, "com.mysql.cj.jdbc.Driver"); From 7fa6f7dfab5ae1753a46f5254c510e9796f6c955 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 16:36:45 +0200 Subject: [PATCH 088/141] feat: specify database type for v7 to v8 migration changeSets in XML files --- .../db/changelog/v7-to-v8-migration.xml | 24 +++++++++---------- .../changelog/v7-to-v8-sqlite-migration.xml | 20 ++++++++-------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Core/src/main/resources/db/changelog/v7-to-v8-migration.xml b/Core/src/main/resources/db/changelog/v7-to-v8-migration.xml index 45298bc526..bbb82881af 100644 --- a/Core/src/main/resources/db/changelog/v7-to-v8-migration.xml +++ b/Core/src/main/resources/db/changelog/v7-to-v8-migration.xml @@ -6,7 +6,7 @@ http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.20.xsd"> - + @@ -35,7 +35,7 @@ - + @@ -88,7 +88,7 @@ - + @@ -111,7 +111,7 @@ onDelete="CASCADE"/> - + @@ -134,7 +134,7 @@ onDelete="CASCADE"/> - + @@ -157,7 +157,7 @@ onDelete="CASCADE"/> - + @@ -181,7 +181,7 @@ - + @@ -206,7 +206,7 @@ - + @@ -229,7 +229,7 @@ onDelete="CASCADE"/> - + @@ -252,7 +252,7 @@ onDelete="CASCADE"/> - + @@ -276,7 +276,7 @@ - + @@ -301,7 +301,7 @@ - + diff --git a/Core/src/main/resources/db/changelog/v7-to-v8-sqlite-migration.xml b/Core/src/main/resources/db/changelog/v7-to-v8-sqlite-migration.xml index 8b0321621c..1bf4f49d26 100644 --- a/Core/src/main/resources/db/changelog/v7-to-v8-sqlite-migration.xml +++ b/Core/src/main/resources/db/changelog/v7-to-v8-sqlite-migration.xml @@ -6,7 +6,7 @@ http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.20.xsd"> - + @@ -59,7 +59,7 @@ - + @@ -109,7 +109,7 @@ - + @@ -148,7 +148,7 @@ onDelete="CASCADE"/> - + @@ -185,7 +185,7 @@ onDelete="CASCADE"/> - + @@ -222,7 +222,7 @@ onDelete="CASCADE"/> - + @@ -267,7 +267,7 @@ - + @@ -316,7 +316,7 @@ - + @@ -354,7 +354,7 @@ - + @@ -395,7 +395,7 @@ - + From 181c07348a4fee0e7b052a6e68aab374264b0910 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 17:15:54 +0200 Subject: [PATCH 089/141] feat: implement H2 database migration support and refactor related services --- .../core/command/DatabaseCommand.java | 75 +-- .../plotsquared/core/command/MainCommand.java | 1 + .../core/configuration/Storage.java | 15 +- .../config/DataSourceProvider.java | 20 +- .../config/DatabaseMigrationService.java | 56 +-- .../persistence/config/InstallationState.java | 18 + .../config/JpaPropertiesProvider.java | 20 + .../config/LiquibaseBootstrap.java | 10 +- ...iquibaseCrossDatabaseMigrationService.java | 33 ++ .../db/changelog/db.changelog-master.xml | 4 - .../db/changelog/v7-to-v8-migration.xml | 110 ++--- .../changelog/v7-to-v8-sqlite-migration.xml | 440 ------------------ 12 files changed, 160 insertions(+), 642 deletions(-) create mode 100644 Core/src/main/java/com/plotsquared/core/persistence/config/InstallationState.java delete mode 100644 Core/src/main/resources/db/changelog/v7-to-v8-sqlite-migration.xml diff --git a/Core/src/main/java/com/plotsquared/core/command/DatabaseCommand.java b/Core/src/main/java/com/plotsquared/core/command/DatabaseCommand.java index f64982914b..663283aff6 100644 --- a/Core/src/main/java/com/plotsquared/core/command/DatabaseCommand.java +++ b/Core/src/main/java/com/plotsquared/core/command/DatabaseCommand.java @@ -19,15 +19,12 @@ package com.plotsquared.core.command; import com.google.inject.Inject; -import com.plotsquared.core.configuration.Storage; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.persistence.config.DatabaseMigrationService; -import com.plotsquared.core.persistence.config.DataSourceProvider; import com.plotsquared.core.persistence.config.LiquibaseCrossDatabaseMigrationService; import com.plotsquared.core.player.PlotPlayer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import javax.sql.DataSource; -import java.sql.Connection; import java.util.concurrent.CompletableFuture; /** @@ -48,16 +45,12 @@ ) public class DatabaseCommand extends SubCommand { - private final DatabaseMigrationService migrationService; - private final DataSourceProvider dataSourceProvider; + private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseCommand.class); + private final LiquibaseCrossDatabaseMigrationService liquibaseMigrationService; @Inject - public DatabaseCommand(DatabaseMigrationService migrationService, - DataSourceProvider dataSourceProvider, - LiquibaseCrossDatabaseMigrationService liquibaseMigrationService) { - this.migrationService = migrationService; - this.dataSourceProvider = dataSourceProvider; + public DatabaseCommand(LiquibaseCrossDatabaseMigrationService liquibaseMigrationService) { this.liquibaseMigrationService = liquibaseMigrationService; } @@ -75,8 +68,8 @@ public boolean onCommand(PlotPlayer player, String[] args) { migrateToMySQL(player); break; - case "migrate-to-sqlite": - migrateToSQLite(player); + case "migrate-to-h2": + migrateToH2(player); break; case "backup": @@ -87,14 +80,6 @@ public boolean onCommand(PlotPlayer player, String[] args) { createBackup(player, args[1]); break; - case "status": - showDatabaseStatus(player); - break; - - case "stats": - showDatabaseStats(player); - break; - default: player.sendMessage(TranslatableCaption.of("database.unknown_subcommand")); player.sendMessage(TranslatableCaption.of("database.available_commands")); @@ -118,17 +103,17 @@ private void migrateToMySQL(PlotPlayer player) { player.sendMessage(TranslatableCaption.of("database.mysql_not_configured")); } catch (Exception e) { player.sendMessage(TranslatableCaption.of("database.migration_failed")); - e.printStackTrace(); + LOGGER.error("Database migration to MySQL failed", e); } }); } - private void migrateToSQLite(PlotPlayer player) { + private void migrateToH2(PlotPlayer player) { player.sendMessage(TranslatableCaption.of("database.migration_sqlite_started")); CompletableFuture.runAsync(() -> { try { - liquibaseMigrationService.migrateToSQLite(); + liquibaseMigrationService.migrateToH2(); player.sendMessage(TranslatableCaption.of("database.migration_completed")); player.sendMessage(TranslatableCaption.of("database.update_config_reminder")); @@ -137,7 +122,7 @@ private void migrateToSQLite(PlotPlayer player) { player.sendMessage(TranslatableCaption.of("database.sqlite_not_configured")); } catch (Exception e) { player.sendMessage(TranslatableCaption.of("database.migration_failed")); - e.printStackTrace(); + LOGGER.error("Database migration to SQLite failed", e); } }); } @@ -157,42 +142,4 @@ private void createBackup(PlotPlayer player, String backupSuffix) { } }); } - - private void showDatabaseStatus(PlotPlayer player) { - try { - DataSource dataSource = dataSourceProvider.createDataSource(); - - try (Connection connection = dataSource.getConnection()) { - String databaseType = Storage.MySQL.USE ? "MySQL" : "SQLite"; - String version = migrationService.getDatabaseVersion(connection); - - player.sendMessage(TranslatableCaption.of("database.status_header")); - player.sendMessage(TranslatableCaption.of("database.status_type", databaseType)); - player.sendMessage(TranslatableCaption.of("database.status_version", version)); - player.sendMessage(TranslatableCaption.of("database.status_prefix", Storage.PREFIX == null ? "none" : Storage.PREFIX)); - } - - } catch (Exception e) { - player.sendMessage(TranslatableCaption.of("database.status_error")); - e.printStackTrace(); - } - } - - private void showDatabaseStats(PlotPlayer player) { - try { - DataSource dataSource = dataSourceProvider.createDataSource(); - - try (Connection connection = dataSource.getConnection()) { - String stats = migrationService.getDatabaseStatistics(connection); - - for (String line : stats.split("\n")) { - player.sendMessage(TranslatableCaption.of("database.stats_line", line)); - } - } - - } catch (Exception e) { - player.sendMessage(TranslatableCaption.of("database.stats_error")); - e.printStackTrace(); - } - } } diff --git a/Core/src/main/java/com/plotsquared/core/command/MainCommand.java b/Core/src/main/java/com/plotsquared/core/command/MainCommand.java index 7c45b96c67..fe6c5cf143 100644 --- a/Core/src/main/java/com/plotsquared/core/command/MainCommand.java +++ b/Core/src/main/java/com/plotsquared/core/command/MainCommand.java @@ -80,6 +80,7 @@ public static MainCommand getInstance() { if (Settings.Web.LEGACY_WEBINTERFACE) { LOGGER.warn("Legacy webinterface is used. Please note that it will be removed in future."); } + commands.add(DatabaseCommand.class); commands.add(Load.class); commands.add(Confirm.class); commands.add(Template.class); diff --git a/Core/src/main/java/com/plotsquared/core/configuration/Storage.java b/Core/src/main/java/com/plotsquared/core/configuration/Storage.java index db637ac70a..9647965a9a 100644 --- a/Core/src/main/java/com/plotsquared/core/configuration/Storage.java +++ b/Core/src/main/java/com/plotsquared/core/configuration/Storage.java @@ -57,10 +57,23 @@ public static final class MySQL { public static final class SQLite { @Comment("Should SQLite be used?") - public static boolean USE = true; + public static boolean USE = false; @Comment("The file to use") public static String DB = "storage"; } + @Comment("H2 section") + public static final class H2 { + @Comment("Should H2 be used?") + public static boolean USE = true; + @Comment("The file to use (without .mv.db ending)") + public static String DB = "storage"; + @Comment("The mode to use (MEMORY, FILE, SERVER)") + public static String MODE = "FILE"; + @Comment("Set additional properties: https://h2database.com/html/features.html#database_url") + public static List PROPERTIES = new ArrayList<>(Collections.singletonList("AUTO_SERVER=TRUE")); + } + } + diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/DataSourceProvider.java b/Core/src/main/java/com/plotsquared/core/persistence/config/DataSourceProvider.java index 3187bfb6c0..1648109f0f 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/DataSourceProvider.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/DataSourceProvider.java @@ -36,7 +36,6 @@ */ @Singleton public final class DataSourceProvider { - private static final Logger LOGGER = Logger.getLogger(DataSourceProvider.class.getName()); /** * Creates a DataSource based on current storage configuration. @@ -51,6 +50,25 @@ public DataSource createDataSource() { config.setUsername(Storage.MySQL.USER); config.setPassword(Storage.MySQL.PASSWORD); config.setDriverClassName("com.mysql.cj.jdbc.Driver"); + } else if (Storage.H2.USE) { + String url; + switch (Storage.H2.MODE.toUpperCase()) { + case "MEMORY": + url = "jdbc:h2:mem:" + Storage.H2.DB; + break; + case "SERVER": + url = "jdbc:h2:tcp://localhost/" + Storage.H2.DB; + break; + case "FILE": + default: + url = "jdbc:h2:file:./" + Storage.H2.DB; + break; + } + if (!Storage.H2.PROPERTIES.isEmpty()) { + url += ";" + String.join(";", Storage.H2.PROPERTIES); + } + config.setJdbcUrl(url); + config.setDriverClassName("org.h2.Driver"); } else if (Storage.SQLite.USE) { String url = "jdbc:sqlite:" + Storage.SQLite.DB + ".db"; config.setJdbcUrl(url); diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/DatabaseMigrationService.java b/Core/src/main/java/com/plotsquared/core/persistence/config/DatabaseMigrationService.java index 59bbf75e92..926f49bacf 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/DatabaseMigrationService.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/DatabaseMigrationService.java @@ -38,7 +38,6 @@ */ @Singleton public final class DatabaseMigrationService { - private static final Logger LOGGER = Logger.getLogger(DatabaseMigrationService.class.getName()); /** * Checks if the current database is using the v7 schema format. @@ -79,59 +78,16 @@ public boolean isV7Database(Connection connection) throws SQLException { /** * Gets the current database version information. */ - public String getDatabaseVersion(Connection connection) throws SQLException { - if (isV7Database(connection)) { - return "v7 (will be migrated to v8 by Liquibase)"; - } else { + public InstallationState getDatabaseVersion(Connection connection) throws SQLException { + if (!isV7Database(connection)) { String prefix = Storage.PREFIX == null ? "" : Storage.PREFIX; try (ResultSet tables = connection.getMetaData().getTables(null, null, prefix + "plot", new String[]{"TABLE"})) { - if (tables.next()) { - return "v8"; - } else { - return "new installation"; + if (!tables.next()) { + return InstallationState.FRESH_INSTALLATION; } } + return InstallationState.NO_MIGRATION_NEEDED; } - } - - /** - * Gets database statistics for informational purposes. - */ - public String getDatabaseStatistics(Connection connection) throws SQLException { - String prefix = Storage.PREFIX == null ? "" : Storage.PREFIX; - StringBuilder stats = new StringBuilder(); - - try { - stats.append("Database Statistics:\n"); - stats.append("- Version: ").append(getDatabaseVersion(connection)).append("\n"); - stats.append("- Prefix: ").append(prefix.isEmpty() ? "none" : prefix).append("\n"); - - // Count plots if table exists - try (ResultSet tables = connection.getMetaData().getTables(null, null, prefix + "plot", new String[]{"TABLE"})) { - if (tables.next()) { - try (var stmt = connection.createStatement(); - var rs = stmt.executeQuery("SELECT COUNT(*) FROM " + prefix + "plot")) { - if (rs.next()) { - stats.append("- Total plots: ").append(rs.getInt(1)).append("\n"); - } - } - } - } - - } catch (SQLException e) { - stats.append("- Error retrieving statistics: ").append(e.getMessage()); - } - - return stats.toString(); - } - - /** - * Checks if a table exists in the database. - */ - public boolean tableExists(Connection connection, String tableName) throws SQLException { - DatabaseMetaData metaData = connection.getMetaData(); - try (ResultSet tables = metaData.getTables(null, null, tableName, new String[]{"TABLE"})) { - return tables.next(); - } + return InstallationState.UPGRADE_FROM_V7; } } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/InstallationState.java b/Core/src/main/java/com/plotsquared/core/persistence/config/InstallationState.java new file mode 100644 index 0000000000..b33d61b6d6 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/InstallationState.java @@ -0,0 +1,18 @@ +package com.plotsquared.core.persistence.config; + +enum InstallationState { + FRESH_INSTALLATION("Fresh installation with no prior data"), + UPGRADE_FROM_V7("Upgrade from version 7.x"), + UPGRADE_FROM_V8("Upgrade from version 8.x"), + NO_MIGRATION_NEEDED("No migration needed, already on latest version"); + + private final String description; + + InstallationState(final String description) { + this.description = description; + } + + public String getDescription() { + return description; + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java b/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java index 3ca46bd4ae..bc3dfb55e2 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java @@ -49,6 +49,26 @@ public Map getProperties() { props.put("jakarta.persistence.jdbc.password", Storage.MySQL.PASSWORD); props.put("jakarta.persistence.jdbc.driver", "com.mysql.cj.jdbc.Driver"); props.put("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect"); + } else if (Storage.H2.USE) { + String url; + switch (Storage.H2.MODE.toUpperCase()) { + case "MEMORY": + url = "jdbc:h2:mem:" + Storage.H2.DB; + break; + case "SERVER": + url = "jdbc:h2:tcp://localhost/" + Storage.H2.DB; + break; + case "FILE": + default: + url = "jdbc:h2:file:./" + Storage.H2.DB; + break; + } + if (!Storage.H2.PROPERTIES.isEmpty()) { + url += ";" + String.join(";", Storage.H2.PROPERTIES); + } + props.put("jakarta.persistence.jdbc.url", url); + props.put("jakarta.persistence.jdbc.driver", "org.h2.Driver"); + props.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect"); } else if (Storage.SQLite.USE) { String url = "jdbc:sqlite:" + Storage.SQLite.DB + ".db"; props.put("jakarta.persistence.jdbc.url", url); diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseBootstrap.java b/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseBootstrap.java index 8ce087e33b..3a76fcecb2 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseBootstrap.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseBootstrap.java @@ -43,14 +43,18 @@ public final class LiquibaseBootstrap { private static final Logger LOGGER = Logger.getLogger(LiquibaseBootstrap.class.getName()); @Inject - public LiquibaseBootstrap(DataSource dataSource, DatabaseMigrationService migrationService) { + public LiquibaseBootstrap(DataSource dataSource, DatabaseMigrationService migrationService, + LiquibaseCrossDatabaseMigrationService liquibaseCrossDatabaseMigrationService) { syncThreadForServiceLoader(() -> { try (Connection connection = dataSource.getConnection()) { Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection)); // Log database version information - String dbVersion = migrationService.getDatabaseVersion(connection); - LOGGER.info("Detected database version: " + dbVersion); + InstallationState dbVersion = migrationService.getDatabaseVersion(connection); + LOGGER.info("Detected database version: " + dbVersion.getDescription()); + if (dbVersion == InstallationState.UPGRADE_FROM_V7) { + liquibaseCrossDatabaseMigrationService.migrateToH2(); + } // Run Liquibase migrations - this will handle both v7->v8 migration and new v8 installations Liquibase liquibase = new Liquibase("db/changelog/db.changelog-master.xml", diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseCrossDatabaseMigrationService.java b/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseCrossDatabaseMigrationService.java index 397a9af0d3..aa01d56b56 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseCrossDatabaseMigrationService.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseCrossDatabaseMigrationService.java @@ -121,6 +121,39 @@ public void migrateToSQLite() { } } + /** + * Migrates from current database to H2 using Liquibase's native capabilities. + */ + public void migrateToH2() { + LOGGER.info("Starting pure Liquibase migration to H2..."); + + if (!Storage.H2.USE) { + throw new IllegalStateException("H2 is not configured. Please configure H2 settings in the config file first."); + } + + try { + // Create H2 datasource using config settings + String h2Url = "jdbc:h2:file:./" + Storage.H2.DB; + if (!Storage.H2.PROPERTIES.isEmpty()) { + h2Url += ";" + String.join(";", Storage.H2.PROPERTIES); + } + DataSource targetDataSource = dataSourceProvider.createDataSource(h2Url, null, null, "org.h2.Driver"); + + // Get current datasource + DataSource sourceDataSource = dataSourceProvider.createDataSource(); + + // Perform migration using pure Liquibase + migrateUsingLiquibaseNative(sourceDataSource, targetDataSource); + + LOGGER.info("Migration to H2 completed successfully."); + + } catch (Exception e) { + LOGGER.severe("Migration to H2 failed: " + e.getMessage()); + e.printStackTrace(); + throw new RuntimeException("Migration to H2 failed", e); + } + } + /** * Migrates from current database to a backup database. */ diff --git a/Core/src/main/resources/db/changelog/db.changelog-master.xml b/Core/src/main/resources/db/changelog/db.changelog-master.xml index a2913cca32..7bfdf6cb3d 100644 --- a/Core/src/main/resources/db/changelog/db.changelog-master.xml +++ b/Core/src/main/resources/db/changelog/db.changelog-master.xml @@ -6,12 +6,8 @@ http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.20.xsd"> - - - - diff --git a/Core/src/main/resources/db/changelog/v7-to-v8-migration.xml b/Core/src/main/resources/db/changelog/v7-to-v8-migration.xml index bbb82881af..1a2270c260 100644 --- a/Core/src/main/resources/db/changelog/v7-to-v8-migration.xml +++ b/Core/src/main/resources/db/changelog/v7-to-v8-migration.xml @@ -5,21 +5,17 @@ xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.20.xsd"> - - + + - - - - - Add auto-increment ID column to existing v7 plot table (MySQL) + Add auto-increment ID column to existing v7 plot table @@ -34,20 +30,16 @@ constraintName="uk_plot_coordinates"/> - - + + - - - - - Create plot_settings table for v8 (MySQL) + Create plot_settings table for v8 @@ -87,19 +79,15 @@ onDelete="CASCADE"/> - - + + - - - - - Update plot_trusted foreign key to use new plot.id (MySQL) + Update plot_trusted foreign key to use new plot.id @@ -111,18 +99,14 @@ onDelete="CASCADE"/> - + - - - - - Update plot_helpers foreign key to use new plot.id (MySQL) + Update plot_helpers foreign key to use new plot.id @@ -134,18 +118,14 @@ onDelete="CASCADE"/> - + - - - - - Update plot_denied foreign key to use new plot.id (MySQL) + Update plot_denied foreign key to use new plot.id @@ -157,18 +137,14 @@ onDelete="CASCADE"/> - + - - - - - Update plot_rating foreign key to use new plot.id (MySQL) + Update plot_rating foreign key to use new plot.id @@ -180,21 +156,17 @@ onDelete="CASCADE"/> - - + + - - - - - Add auto-increment ID column to existing v7 cluster table (MySQL) + Add auto-increment ID column to existing v7 cluster table @@ -205,19 +177,15 @@ - - + + - - - - - Update cluster_helpers foreign key to use new cluster.id (MySQL) + Update cluster_helpers foreign key to use new cluster.id @@ -229,18 +197,14 @@ onDelete="CASCADE"/> - + - - - - - Update cluster_invited foreign key to use new cluster.id (MySQL) + Update cluster_invited foreign key to use new cluster.id @@ -252,18 +216,14 @@ onDelete="CASCADE"/> - + - - - - - Update cluster_settings foreign key to use new cluster.id (MySQL) + Update cluster_settings foreign key to use new cluster.id @@ -275,21 +235,17 @@ onDelete="CASCADE"/> - - + + - - - - - Add auto-increment meta_id column to existing v7 player_meta table (MySQL) + Add auto-increment meta_id column to existing v7 player_meta table @@ -300,20 +256,16 @@ - - + + - - - - - Create plot_flags table if missing (MySQL) + Create plot_flags table if missing diff --git a/Core/src/main/resources/db/changelog/v7-to-v8-sqlite-migration.xml b/Core/src/main/resources/db/changelog/v7-to-v8-sqlite-migration.xml deleted file mode 100644 index 1bf4f49d26..0000000000 --- a/Core/src/main/resources/db/changelog/v7-to-v8-sqlite-migration.xml +++ /dev/null @@ -1,440 +0,0 @@ - - - - - - - - - - - - - - - Recreate plot table with ID column for SQLite v7 to v8 migration - - - - - - - - - - - - - - - - - - - - - - - - - - INSERT INTO ${prefix}plot_new (plot_id_x, plot_id_z, world, owner, timestamp) - SELECT plot_id_x, plot_id_z, world, owner, timestamp FROM ${prefix}plot - - - - - - - ALTER TABLE ${prefix}plot_new RENAME TO ${prefix}plot - - - - - - - - - - - - - - - - Create plot_settings table for SQLite v8 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Update plot_trusted to use new plot IDs for SQLite - - - - - - - - - - - - - - INSERT INTO ${prefix}plot_trusted_new (plot_plot_id, user_uuid) - SELECT p.id, pt.user_uuid - FROM ${prefix}plot_trusted pt - JOIN ${prefix}plot p ON pt.plot_id_x = p.plot_id_x AND pt.plot_id_z = p.plot_id_z AND pt.world = p.world - - - - ALTER TABLE ${prefix}plot_trusted_new RENAME TO ${prefix}plot_trusted - - - - - - - - - - - - - Update plot_helpers to use new plot IDs for SQLite - - - - - - - - - - - - INSERT INTO ${prefix}plot_helpers_new (plot_plot_id, user_uuid) - SELECT p.id, ph.user_uuid - FROM ${prefix}plot_helpers ph - JOIN ${prefix}plot p ON ph.plot_id_x = p.plot_id_x AND ph.plot_id_z = p.plot_id_z AND ph.world = p.world - - - - ALTER TABLE ${prefix}plot_helpers_new RENAME TO ${prefix}plot_helpers - - - - - - - - - - - - - Update plot_denied to use new plot IDs for SQLite - - - - - - - - - - - - INSERT INTO ${prefix}plot_denied_new (plot_plot_id, user_uuid) - SELECT p.id, pd.user_uuid - FROM ${prefix}plot_denied pd - JOIN ${prefix}plot p ON pd.plot_id_x = p.plot_id_x AND pd.plot_id_z = p.plot_id_z AND pd.world = p.world - - - - ALTER TABLE ${prefix}plot_denied_new RENAME TO ${prefix}plot_denied - - - - - - - - - - - - - Update plot_rating to use new plot IDs for SQLite - - - - - - - - - - - - - - - INSERT INTO ${prefix}plot_rating_new (plot_plot_id, rating, player) - SELECT p.id, pr.rating, pr.player - FROM ${prefix}plot_rating pr - JOIN ${prefix}plot p ON pr.plot_id_x = p.plot_id_x AND pr.plot_id_z = p.plot_id_z AND pr.world = p.world - - - - ALTER TABLE ${prefix}plot_rating_new RENAME TO ${prefix}plot_rating - - - - - - - - - - - - - - - - - - Recreate cluster table with ID column for SQLite v7 to v8 migration - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - INSERT INTO ${prefix}cluster_new (pos1_x, pos1_z, pos2_x, pos2_z, owner, world, timestamp) - SELECT pos1_x, pos1_z, pos2_x, pos2_z, owner, world, timestamp FROM ${prefix}cluster - - - - ALTER TABLE ${prefix}cluster_new RENAME TO ${prefix}cluster - - - - - - - - - - - - Update cluster_helpers to use new cluster IDs for SQLite - - - - - - - - - - - - INSERT INTO ${prefix}cluster_helpers_new (cluster_id, user_uuid) - SELECT c.id, ch.user_uuid - FROM ${prefix}cluster_helpers ch - JOIN ${prefix}cluster c ON ch.cluster_id = c.id - - - - ALTER TABLE ${prefix}cluster_helpers_new RENAME TO ${prefix}cluster_helpers - - - - - - - - - - - - - - - - Add auto-increment meta_id column to existing v7 player_meta table (SQLite) - - - - - - - - - - - - - - - - - - INSERT INTO ${prefix}player_meta_new (uuid, key, value) - SELECT uuid, key, value FROM ${prefix}player_meta - - - - ALTER TABLE ${prefix}player_meta_new RENAME TO ${prefix}player_meta - - - - - - - - - - - - - - - Create plot_flags table if missing (SQLite) - - - - - - - - - - - - - - - - - - - - - - - - - - From 90a2c90933d104729c54b15c0d4a0df9536e28d5 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 17:17:49 +0200 Subject: [PATCH 090/141] feat: add H2 database support and include JAXB runtime dependency --- Core/build.gradle.kts | 3 ++- gradle/libs.versions.toml | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Core/build.gradle.kts b/Core/build.gradle.kts index 5bd5a8b0ce..3a7899e013 100644 --- a/Core/build.gradle.kts +++ b/Core/build.gradle.kts @@ -49,13 +49,14 @@ dependencies { api(libs.hibernateCore) api(libs.hibernateHikariCp) api(libs.hikari) - runtimeOnly(libs.jaxbRuntime) api(libs.hibernateCommunityDialects) api(libs.jpaApi) api(libs.liquibaseCore) runtimeOnly(libs.mariadbJavaClient) runtimeOnly(libs.sqliteJdbc) + runtimeOnly(libs.h2) + runtimeOnly(libs.jaxbRuntime) } tasks.processResources { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d73e094e6a..a2d3c34b6e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -41,6 +41,7 @@ jaxbRuntime = "4.0.5" # JDBC Drivers mariadb-java-client = "3.5.5" sqlite-jdbc = "3.50.3.0" +h2 = "2.3.232" # Gradle plugins shadow = "8.3.9" @@ -98,6 +99,7 @@ jaxbRuntime = { group = "org.glassfish.jaxb", name = "jaxb-runtime", version.ref # JDBC Drivers mariadbJavaClient = { group = "org.mariadb.jdbc", name = "mariadb-java-client", version.ref = "mariadb-java-client" } sqliteJdbc = { group = "org.xerial", name = "sqlite-jdbc", version.ref = "sqlite-jdbc" } +h2 = { group = "com.h2database", name = "h2", version.ref = "h2" } [plugins] shadow = { id = "com.gradleup.shadow", version.ref = "shadow" } From e49cac559e62b5a4cf9cff6e36708b39432b91c6 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz <6745190+TheMeinerLP@users.noreply.github.com> Date: Fri, 5 Sep 2025 18:16:42 +0200 Subject: [PATCH 091/141] feat: remove SQLite support and clean up database migration logic --- .../core/command/DatabaseCommand.java | 25 ----- .../config/DataSourceProvider.java | 22 +--- .../config/JpaPropertiesProvider.java | 5 - .../config/LiquibaseBootstrap.java | 15 ++- ...iquibaseCrossDatabaseMigrationService.java | 100 ++---------------- 5 files changed, 24 insertions(+), 143 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/command/DatabaseCommand.java b/Core/src/main/java/com/plotsquared/core/command/DatabaseCommand.java index 663283aff6..2ba5ccafc8 100644 --- a/Core/src/main/java/com/plotsquared/core/command/DatabaseCommand.java +++ b/Core/src/main/java/com/plotsquared/core/command/DatabaseCommand.java @@ -71,15 +71,6 @@ public boolean onCommand(PlotPlayer player, String[] args) { case "migrate-to-h2": migrateToH2(player); break; - - case "backup": - if (args.length < 2) { - player.sendMessage(TranslatableCaption.of("database.backup_usage")); - return false; - } - createBackup(player, args[1]); - break; - default: player.sendMessage(TranslatableCaption.of("database.unknown_subcommand")); player.sendMessage(TranslatableCaption.of("database.available_commands")); @@ -126,20 +117,4 @@ private void migrateToH2(PlotPlayer player) { } }); } - - private void createBackup(PlotPlayer player, String backupSuffix) { - player.sendMessage(TranslatableCaption.of("database.backup_started")); - - CompletableFuture.runAsync(() -> { - try { - liquibaseMigrationService.migrateToBackupDatabase(backupSuffix); - - player.sendMessage(TranslatableCaption.of("database.backup_completed")); - - } catch (Exception e) { - player.sendMessage(TranslatableCaption.of("database.backup_failed")); - e.printStackTrace(); - } - }); - } } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/DataSourceProvider.java b/Core/src/main/java/com/plotsquared/core/persistence/config/DataSourceProvider.java index 1648109f0f..5092d0802d 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/DataSourceProvider.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/DataSourceProvider.java @@ -51,28 +51,16 @@ public DataSource createDataSource() { config.setPassword(Storage.MySQL.PASSWORD); config.setDriverClassName("com.mysql.cj.jdbc.Driver"); } else if (Storage.H2.USE) { - String url; - switch (Storage.H2.MODE.toUpperCase()) { - case "MEMORY": - url = "jdbc:h2:mem:" + Storage.H2.DB; - break; - case "SERVER": - url = "jdbc:h2:tcp://localhost/" + Storage.H2.DB; - break; - case "FILE": - default: - url = "jdbc:h2:file:./" + Storage.H2.DB; - break; - } + String url = switch (Storage.H2.MODE.toUpperCase()) { + case "MEMORY" -> "jdbc:h2:mem:" + Storage.H2.DB; + case "SERVER" -> "jdbc:h2:tcp://localhost/" + Storage.H2.DB; + default -> "jdbc:h2:file:./" + Storage.H2.DB; + }; if (!Storage.H2.PROPERTIES.isEmpty()) { url += ";" + String.join(";", Storage.H2.PROPERTIES); } config.setJdbcUrl(url); config.setDriverClassName("org.h2.Driver"); - } else if (Storage.SQLite.USE) { - String url = "jdbc:sqlite:" + Storage.SQLite.DB + ".db"; - config.setJdbcUrl(url); - config.setDriverClassName("org.sqlite.JDBC"); } config.setMaximumPoolSize(10); diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java b/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java index bc3dfb55e2..99cd2712b3 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java @@ -69,11 +69,6 @@ public Map getProperties() { props.put("jakarta.persistence.jdbc.url", url); props.put("jakarta.persistence.jdbc.driver", "org.h2.Driver"); props.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect"); - } else if (Storage.SQLite.USE) { - String url = "jdbc:sqlite:" + Storage.SQLite.DB + ".db"; - props.put("jakarta.persistence.jdbc.url", url); - props.put("jakarta.persistence.jdbc.driver", "org.sqlite.JDBC"); - props.put("hibernate.dialect", "org.hibernate.community.dialect.SQLiteDialect"); } // Schema is managed by Liquibase; only validate with Hibernate diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseBootstrap.java b/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseBootstrap.java index 3a76fcecb2..33f806fe04 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseBootstrap.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseBootstrap.java @@ -20,6 +20,9 @@ import com.google.inject.Inject; import com.google.inject.Singleton; +import com.plotsquared.core.configuration.Storage; +import liquibase.Contexts; +import liquibase.LabelExpression; import liquibase.Liquibase; import liquibase.database.Database; import liquibase.database.DatabaseFactory; @@ -50,9 +53,9 @@ public LiquibaseBootstrap(DataSource dataSource, DatabaseMigrationService migrat Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection)); // Log database version information - InstallationState dbVersion = migrationService.getDatabaseVersion(connection); - LOGGER.info("Detected database version: " + dbVersion.getDescription()); - if (dbVersion == InstallationState.UPGRADE_FROM_V7) { + InstallationState installationState = migrationService.getDatabaseVersion(connection); + LOGGER.info("Detected database version: " + installationState.getDescription()); + if (installationState == InstallationState.UPGRADE_FROM_V7) { liquibaseCrossDatabaseMigrationService.migrateToH2(); } @@ -60,12 +63,14 @@ public LiquibaseBootstrap(DataSource dataSource, DatabaseMigrationService migrat Liquibase liquibase = new Liquibase("db/changelog/db.changelog-master.xml", new ClassLoaderResourceAccessor(), database); - liquibase.update(""); + liquibase.setChangeLogParameter("PREFIX", Storage.PREFIX == null ? "" : Storage.PREFIX); + liquibase.setChangeLogParameter("prefix", Storage.PREFIX == null ? "" : Storage.PREFIX); + + liquibase.update(new Contexts(), new LabelExpression()); LOGGER.info("Liquibase migration completed successfully."); } catch (Exception e) { LOGGER.severe("Liquibase migration failed: " + e.getMessage()); - throw new RuntimeException("Database migration failed", e); } }); } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseCrossDatabaseMigrationService.java b/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseCrossDatabaseMigrationService.java index aa01d56b56..f0eeb7425f 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseCrossDatabaseMigrationService.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseCrossDatabaseMigrationService.java @@ -21,6 +21,8 @@ import com.google.inject.Inject; import com.google.inject.Singleton; import com.plotsquared.core.configuration.Storage; +import liquibase.Contexts; +import liquibase.LabelExpression; import liquibase.Liquibase; import liquibase.database.Database; import liquibase.database.DatabaseFactory; @@ -91,36 +93,6 @@ public void migrateToMySQL() { } } - /** - * Migrates from current database to SQLite using Liquibase's native capabilities. - */ - public void migrateToSQLite() { - LOGGER.info("Starting pure Liquibase migration to SQLite..."); - - if (!Storage.SQLite.USE) { - throw new IllegalStateException("SQLite is not configured. Please configure SQLite settings in the config file first."); - } - - try { - // Create SQLite datasource using config settings - String sqliteUrl = "jdbc:sqlite:" + Storage.SQLite.DB + ".db"; - DataSource targetDataSource = dataSourceProvider.createDataSource(sqliteUrl, null, null, "org.sqlite.JDBC"); - - // Get current datasource - DataSource sourceDataSource = dataSourceProvider.createDataSource(); - - // Perform migration using pure Liquibase - migrateUsingLiquibaseNative(sourceDataSource, targetDataSource); - - LOGGER.info("Migration to SQLite completed successfully."); - - } catch (Exception e) { - LOGGER.severe("Migration to SQLite failed: " + e.getMessage()); - e.printStackTrace(); - throw new RuntimeException("Migration to SQLite failed", e); - } - } - /** * Migrates from current database to H2 using Liquibase's native capabilities. */ @@ -154,48 +126,13 @@ public void migrateToH2() { } } - /** - * Migrates from current database to a backup database. - */ - public void migrateToBackupDatabase(String backupSuffix) { - LOGGER.info("Starting migration to backup database with suffix: " + backupSuffix); - - try { - DataSource sourceDataSource = dataSourceProvider.createDataSource(); - DataSource targetDataSource; - - if (Storage.MySQL.USE) { - // Create backup MySQL database - String backupDatabase = Storage.MySQL.DATABASE + "_" + backupSuffix; - String mysqlUrl = "jdbc:mysql://" + Storage.MySQL.HOST + ":" + Storage.MySQL.PORT + "/" + backupDatabase + - "?" + String.join("&", Storage.MySQL.PROPERTIES) + "&createDatabaseIfNotExist=true"; - targetDataSource = dataSourceProvider.createDataSource(mysqlUrl, Storage.MySQL.USER, Storage.MySQL.PASSWORD, "com.mysql.cj.jdbc.Driver"); - } else { - // Create backup SQLite database - String backupFile = Storage.SQLite.DB + "_" + backupSuffix; - String sqliteUrl = "jdbc:sqlite:" + backupFile + ".db"; - targetDataSource = dataSourceProvider.createDataSource(sqliteUrl, null, null, "org.sqlite.JDBC"); - } - - // Perform migration using pure Liquibase - migrateUsingLiquibaseNative(sourceDataSource, targetDataSource); - - LOGGER.info("Migration to backup database completed successfully."); - - } catch (Exception e) { - LOGGER.severe("Migration to backup database failed: " + e.getMessage()); - e.printStackTrace(); - throw new RuntimeException("Migration to backup database failed", e); - } - } - /** * Performs the actual migration using Liquibase's native generateChangeLog functionality. * This approach eliminates the need for CSV export/import and uses pure Liquibase operations. */ private void migrateUsingLiquibaseNative(DataSource sourceDataSource, DataSource targetDataSource) throws Exception { // Create temporary file for the generated changelog - Path tempChangelog = Files.createTempFile("plotsquared-migration-", ".xml"); + Path tempChangelog = Files.createTempFile(Path.of(""),"plotsquared-migration-", ".xml"); try (Connection sourceConnection = sourceDataSource.getConnection(); Connection targetConnection = targetDataSource.getConnection()) { @@ -207,7 +144,7 @@ private void migrateUsingLiquibaseNative(DataSource sourceDataSource, DataSource LOGGER.info("Creating target database schema..."); Liquibase schemaLiquibase = new Liquibase("db/changelog/db.changelog-master.xml", new ClassLoaderResourceAccessor(), targetDatabase); - schemaLiquibase.update(""); + schemaLiquibase.update(new Contexts(), new LabelExpression()); // Step 2: Generate changelog with data from source database LOGGER.info("Generating changelog with data from source database..."); @@ -217,7 +154,10 @@ private void migrateUsingLiquibaseNative(DataSource sourceDataSource, DataSource LOGGER.info("Applying data to target database..."); Liquibase dataLiquibase = new Liquibase(tempChangelog.toString(), new ClassLoaderResourceAccessor(), targetDatabase); - dataLiquibase.update(""); + dataLiquibase.setChangeLogParameter("PREFIX", Storage.PREFIX == null ? "" : Storage.PREFIX); + dataLiquibase.setChangeLogParameter("prefix", Storage.PREFIX == null ? "" : Storage.PREFIX); + + dataLiquibase.update(new Contexts(), new LabelExpression()); LOGGER.info("Pure Liquibase migration completed successfully."); @@ -242,8 +182,7 @@ private void generateDataChangeLog(Database sourceDatabase, Path outputFile) thr // Generate changelog including data // This uses Liquibase's built-in generateChangeLog with data option - generateChangeLogUsingDiff(sourceDatabase, sourceDatabase, outputFile);// import liquibase.snapshot.DatabaseSnapshot; // Entfernen - // import liquibase.structure.DatabaseSnapshot; // Entfernen + generateChangeLogUsingDiff(sourceDatabase, sourceDatabase, outputFile); } catch (Exception e) { LOGGER.severe("Failed to generate data changelog: " + e.getMessage()); @@ -312,25 +251,4 @@ public boolean validateMigration(DataSource sourceDataSource, DataSource targetD return false; } } - - /** - * Gets migration statistics without hacky record counting. - */ - public String getMigrationInfo(DataSource dataSource) { - try (Connection connection = dataSource.getConnection()) { - Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection)); - - // Use Liquibase to get database info - StringBuilder info = new StringBuilder(); - info.append("Database Type: ").append(database.getDatabaseProductName()).append("\n"); - info.append("Database Version: ").append(database.getDatabaseProductVersion()).append("\n"); - info.append("Default Schema: ").append(database.getDefaultSchemaName()).append("\n"); - - return info.toString(); - - } catch (Exception e) { - LOGGER.warning("Error getting migration info: " + e.getMessage()); - return "Error retrieving database information"; - } - } } From 4d65f89bda9022589754137fd7a41e99eb5989c0 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sat, 6 Sep 2025 22:27:50 +0200 Subject: [PATCH 092/141] feat: implement UUID services for EssentialsX, LuckPerms, OfflinePlayer, Paper, and SquirrelID --- .../plotsquared/bukkit/BukkitPlatform.java | 146 ++++++++++-------- .../bukkit/uuid/EssentialsUUIDService.java | 66 ++++++++ .../bukkit/uuid/LuckPermsUUIDService.java | 81 ++++++++++ .../bukkit/uuid/OfflinePlayerUUIDService.java | 81 ++++++++++ .../bukkit/uuid/PaperUUIDService.java | 60 +++++++ .../bukkit/uuid/SquirrelIdUUIDService.java | 112 ++++++++++++++ 6 files changed, 484 insertions(+), 62 deletions(-) create mode 100644 Bukkit/src/main/java/com/plotsquared/bukkit/uuid/EssentialsUUIDService.java create mode 100644 Bukkit/src/main/java/com/plotsquared/bukkit/uuid/LuckPermsUUIDService.java create mode 100644 Bukkit/src/main/java/com/plotsquared/bukkit/uuid/OfflinePlayerUUIDService.java create mode 100644 Bukkit/src/main/java/com/plotsquared/bukkit/uuid/PaperUUIDService.java create mode 100644 Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SquirrelIdUUIDService.java diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java index 4570989e32..4dea647b3f 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java @@ -54,6 +54,11 @@ import com.plotsquared.bukkit.util.task.BukkitTaskManager; import com.plotsquared.bukkit.util.task.PaperTimeConverter; import com.plotsquared.bukkit.util.task.SpigotTimeConverter; +import com.plotsquared.bukkit.uuid.EssentialsUUIDService; +import com.plotsquared.bukkit.uuid.LuckPermsUUIDService; +import com.plotsquared.bukkit.uuid.OfflinePlayerUUIDService; +import com.plotsquared.bukkit.uuid.PaperUUIDService; +import com.plotsquared.bukkit.uuid.SquirrelIdUUIDService; import com.plotsquared.core.PlotPlatform; import com.plotsquared.core.PlotSquared; import com.plotsquared.core.backup.BackupManager; @@ -65,12 +70,15 @@ import com.plotsquared.core.configuration.Storage; import com.plotsquared.core.configuration.caption.ChatFormatter; import com.plotsquared.core.configuration.file.YamlConfiguration; +import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.events.RemoveRoadEntityEvent; import com.plotsquared.core.events.Result; import com.plotsquared.core.generator.GeneratorWrapper; import com.plotsquared.core.generator.IndependentPlotGenerator; import com.plotsquared.core.generator.SingleWorldGenerator; +import com.plotsquared.core.inject.annotations.BackgroundPipeline; import com.plotsquared.core.inject.annotations.DefaultGenerator; +import com.plotsquared.core.inject.annotations.ImpromptuPipeline; import com.plotsquared.core.inject.annotations.WorldConfig; import com.plotsquared.core.inject.annotations.WorldFile; import com.plotsquared.core.inject.modules.PlotSquaredModule; @@ -91,6 +99,7 @@ import com.plotsquared.core.setup.PlotAreaBuilder; import com.plotsquared.core.setup.SettingsNodesWrapper; import com.plotsquared.core.util.EventDispatcher; +import com.plotsquared.core.util.FileUtils; import com.plotsquared.core.util.PlatformWorldManager; import com.plotsquared.core.util.PlayerManager; import com.plotsquared.core.util.PremiumVerification; @@ -100,6 +109,8 @@ import com.plotsquared.core.util.task.TaskManager; import com.plotsquared.core.util.task.TaskTime; import com.plotsquared.core.uuid.CacheUUIDService; +import com.plotsquared.core.uuid.UUIDPipeline; +import com.plotsquared.core.uuid.offline.OfflineModeUUIDService; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.bukkit.BukkitAdapter; import io.papermc.lib.PaperLib; @@ -197,6 +208,12 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl @Inject private BackupManager backupManager; @Inject + @ImpromptuPipeline + private UUIDPipeline impromptuPipeline; + @Inject + @BackgroundPipeline + private UUIDPipeline backgroundPipeline; + @Inject private PlatformWorldManager worldManager; private Locale serverLocale; @@ -415,6 +432,73 @@ public void onEnable() { // Once the server has loaded force updating all generators known to PlotSquared TaskManager.runTaskLater(() -> PlotSquared.platform().setupUtils().updateGenerators(true), TaskTime.ticks(1L)); + // Services are accessed in order + final CacheUUIDService cacheUUIDService = new CacheUUIDService(Settings.UUID.UUID_CACHE_SIZE); + this.impromptuPipeline.registerService(cacheUUIDService); + this.backgroundPipeline.registerService(cacheUUIDService); + this.impromptuPipeline.registerConsumer(cacheUUIDService); + this.backgroundPipeline.registerConsumer(cacheUUIDService); + + // Now, if the server is in offline mode we can only use profiles and direct UUID + // access, and so we skip the player profile stuff as well as SquirrelID (Mojang lookups) + if (Settings.UUID.OFFLINE) { + final OfflineModeUUIDService offlineModeUUIDService = new OfflineModeUUIDService(); + this.impromptuPipeline.registerService(offlineModeUUIDService); + this.backgroundPipeline.registerService(offlineModeUUIDService); + LOGGER.info("(UUID) Using the offline mode UUID service"); + } + + if (Settings.UUID.SERVICE_BUKKIT) { + final OfflinePlayerUUIDService offlinePlayerUUIDService = new OfflinePlayerUUIDService(); + this.impromptuPipeline.registerService(offlinePlayerUUIDService); + this.backgroundPipeline.registerService(offlinePlayerUUIDService); + } + + final LuckPermsUUIDService luckPermsUUIDService; + if (Settings.UUID.SERVICE_LUCKPERMS && Bukkit.getPluginManager().getPlugin("LuckPerms") != null) { + luckPermsUUIDService = new LuckPermsUUIDService(); + LOGGER.info("(UUID) Using LuckPerms as a complementary UUID service"); + } else { + luckPermsUUIDService = null; + } + + final EssentialsUUIDService essentialsUUIDService; + if (Settings.UUID.SERVICE_ESSENTIALSX && Bukkit.getPluginManager().getPlugin("Essentials") != null) { + essentialsUUIDService = new EssentialsUUIDService(); + LOGGER.info("(UUID) Using EssentialsX as a complementary UUID service"); + } else { + essentialsUUIDService = null; + } + + if (!Settings.UUID.OFFLINE) { + // If running Paper we'll also try to use their profiles + if (Bukkit.getOnlineMode() && PaperLib.isPaper() && Settings.UUID.SERVICE_PAPER) { + final PaperUUIDService paperUUIDService = new PaperUUIDService(); + this.impromptuPipeline.registerService(paperUUIDService); + this.backgroundPipeline.registerService(paperUUIDService); + LOGGER.info("(UUID) Using Paper as a complementary UUID service"); + } + + // Plugin providers + if (luckPermsUUIDService != null) { + this.impromptuPipeline.registerService(luckPermsUUIDService); + this.backgroundPipeline.registerService(luckPermsUUIDService); + } + if (essentialsUUIDService != null) { + this.impromptuPipeline.registerService(essentialsUUIDService); + this.backgroundPipeline.registerService(essentialsUUIDService); + } + + if (Settings.UUID.IMPROMPTU_SERVICE_MOJANG_API) { + final SquirrelIdUUIDService impromptuMojangService = new SquirrelIdUUIDService(Settings.UUID.IMPROMPTU_LIMIT); + this.impromptuPipeline.registerService(impromptuMojangService); + } + final SquirrelIdUUIDService backgroundMojangService = new SquirrelIdUUIDService(Settings.UUID.BACKGROUND_LIMIT); + this.backgroundPipeline.registerService(backgroundMojangService); + } + + this.impromptuPipeline.storeImmediately("*", DBFunc.EVERYONE); + if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) { injector.getInstance(PAPIPlaceholders.class).register(); if (Settings.Enabled_Components.EXTERNAL_PLACEHOLDERS) { @@ -537,68 +621,6 @@ private void unload() { } } - private void startUuidCaching( - final @NonNull CacheUUIDService cacheUUIDService - ) { - // Record all unique UUID's and put them into a queue - final Set uuidSet = new HashSet<>(); - PlotSquared.get().forEachPlotRaw(plot -> { - uuidSet.add(plot.getOwnerAbs()); - uuidSet.addAll(plot.getMembers()); - uuidSet.addAll(plot.getTrusted()); - uuidSet.addAll(plot.getDenied()); - }); - final Queue uuidQueue = new LinkedBlockingQueue<>(uuidSet); - - LOGGER.info("(UUID) {} UUIDs will be cached", uuidQueue.size()); - - Executors.newSingleThreadScheduledExecutor().schedule(() -> { - // Begin by reading all the SQLite cache at once - // Now fetch names for all known UUIDs - final int totalSize = uuidQueue.size(); - int read = 0; - LOGGER.info("(UUID) PlotSquared will fetch UUIDs in groups of {}", Settings.UUID.BACKGROUND_LIMIT); - final List uuidList = new ArrayList<>(Settings.UUID.BACKGROUND_LIMIT); - - // Used to indicate that the second retrieval has been attempted - boolean secondRun = false; - - while (!uuidQueue.isEmpty() || !uuidList.isEmpty()) { - if (!uuidList.isEmpty() && secondRun) { - LOGGER.warn("(UUID) Giving up on last batch. Fetching new batch instead"); - uuidList.clear(); - } - if (uuidList.isEmpty()) { - // Retrieve the secondRun variable to indicate that we're retrieving a - // fresh batch - secondRun = false; - // Populate the request list - for (int i = 0; i < Settings.UUID.BACKGROUND_LIMIT && !uuidQueue.isEmpty(); i++) { - uuidList.add(uuidQueue.poll()); - read++; - } - } else { - // If the list isn't empty then this is a second run for - // an old batch, so we re-use the patch - secondRun = true; - } - try { - PlotSquared.get().getBackgroundUUIDPipeline().getNames(uuidList).get(); - // Clear the list if we successfully index all the names - uuidList.clear(); - // Print progress - final double percentage = ((double) read / (double) totalSize) * 100.0D; - if (Settings.DEBUG) { - LOGGER.info("(UUID) PlotSquared has cached {} of UUIDs", String.format("%.1f%%", percentage)); - } - } catch (final InterruptedException | ExecutionException e) { - LOGGER.error("(UUID) Failed to retrieve last batch. Will try again", e); - } - } - LOGGER.info("(UUID) PlotSquared has cached all UUIDs"); - }, 10, TimeUnit.SECONDS); - } - @Override public void onDisable() { PlotSquared.get().disable(); diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/EssentialsUUIDService.java b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/EssentialsUUIDService.java new file mode 100644 index 0000000000..e87b8487bc --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/EssentialsUUIDService.java @@ -0,0 +1,66 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.bukkit.uuid; + +import com.earth2me.essentials.Essentials; +import com.earth2me.essentials.User; +import com.plotsquared.core.uuid.UUIDMapping; +import com.plotsquared.core.uuid.UUIDService; +import org.checkerframework.checker.nullness.qual.NonNull; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +/** + * UUID service using the EssentialsX API + */ +public class EssentialsUUIDService implements UUIDService { + + private final Essentials essentials; + + public EssentialsUUIDService() { + this.essentials = Essentials.getPlugin(Essentials.class); + } + + @Override + public @NonNull List getNames(final @NonNull List uuids) { + return Collections.emptyList(); + } + + @Override + public @NonNull List getUUIDs(final @NonNull List usernames) { + final List mappings = new ArrayList<>(usernames.size()); + for (final String username : usernames) { + try { + final User user = essentials.getUser(username); + if (user != null) { + final UUID uuid = user.getConfigUUID(); + if (uuid != null) { + mappings.add(new UUIDMapping(uuid, username)); + } + } + } catch (final Exception ignored) { + } + } + return mappings; + } + +} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/LuckPermsUUIDService.java b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/LuckPermsUUIDService.java new file mode 100644 index 0000000000..20e26b53e9 --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/LuckPermsUUIDService.java @@ -0,0 +1,81 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.bukkit.uuid; + +import com.plotsquared.core.uuid.UUIDMapping; +import com.plotsquared.core.uuid.UUIDService; +import net.luckperms.api.LuckPerms; +import net.luckperms.api.model.user.UserManager; +import org.bukkit.Bukkit; +import org.bukkit.plugin.RegisteredServiceProvider; +import org.checkerframework.checker.nullness.qual.NonNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * UUID service that uses the LuckPerms API + */ +public class LuckPermsUUIDService implements UUIDService { + + private final LuckPerms luckPerms; + + public LuckPermsUUIDService() { + final RegisteredServiceProvider provider = Bukkit.getServicesManager().getRegistration(LuckPerms.class); + if (provider != null) { + this.luckPerms = provider.getProvider(); + } else { + throw new IllegalStateException("LuckPerms not available"); + } + } + + @Override + public @NonNull List getNames(final @NonNull List uuids) { + final List mappings = new ArrayList<>(uuids.size()); + final UserManager userManager = this.luckPerms.getUserManager(); + for (final UUID uuid : uuids) { + try { + final String username = userManager.lookupUsername(uuid).get(); + if (username != null) { + mappings.add(new UUIDMapping(uuid, username)); + } + } catch (final Exception ignored) { + } + } + return mappings; + } + + @Override + public @NonNull List getUUIDs(final @NonNull List usernames) { + final List mappings = new ArrayList<>(usernames.size()); + final UserManager userManager = this.luckPerms.getUserManager(); + for (final String username : usernames) { + try { + final UUID uuid = userManager.lookupUniqueId(username).get(); + if (username != null) { + mappings.add(new UUIDMapping(uuid, username)); + } + } catch (final Exception ignored) { + } + } + return mappings; + } + +} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/OfflinePlayerUUIDService.java b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/OfflinePlayerUUIDService.java new file mode 100644 index 0000000000..4c48c016d7 --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/OfflinePlayerUUIDService.java @@ -0,0 +1,81 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.bukkit.uuid; + +import com.google.common.base.Charsets; +import com.plotsquared.core.configuration.Settings; +import com.plotsquared.core.uuid.UUIDMapping; +import com.plotsquared.core.uuid.UUIDService; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.checkerframework.checker.nullness.qual.NonNull; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +/** + * UUID service that use {@link org.bukkit.OfflinePlayer offline players} + */ +public class OfflinePlayerUUIDService implements UUIDService { + + @Override + public @NonNull List getNames(final @NonNull List uuids) { + if (Settings.UUID.FORCE_LOWERCASE || Bukkit.getWorlds().isEmpty()) { + return Collections.emptyList(); // This is useless now + } + final List wrappers = new ArrayList<>(uuids.size()); + for (final UUID uuid : uuids) { + final OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(uuid); + try { + if (offlinePlayer.hasPlayedBefore()) { + wrappers.add(new UUIDMapping(uuid, offlinePlayer.getName())); + } + } catch (final Exception ignored) { + } /* This can be safely ignored. If this happens, it is + probably because it's called before the worlds have + been loaded. This is bad, but does not break anything */ + } + return wrappers; + } + + @Override + public @NonNull List getUUIDs(final @NonNull List usernames) { + final List wrappers = new ArrayList<>(usernames.size()); + for (final String username : usernames) { + if (Settings.UUID.OFFLINE) { + if (Settings.UUID.FORCE_LOWERCASE) { + wrappers.add(new UUIDMapping(UUID.nameUUIDFromBytes(("OfflinePlayer:" + + username.toLowerCase()).getBytes(Charsets.UTF_8)), username)); + } else { + wrappers.add(new UUIDMapping(UUID.nameUUIDFromBytes(("OfflinePlayer:" + + username).getBytes(Charsets.UTF_8)), username)); + } + } else { + final OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(username); + if (offlinePlayer.hasPlayedBefore()) { + wrappers.add(new UUIDMapping(offlinePlayer.getUniqueId(), offlinePlayer.getName())); + } + } + } + return wrappers; + } + +} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/PaperUUIDService.java b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/PaperUUIDService.java new file mode 100644 index 0000000000..296cb47c51 --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/PaperUUIDService.java @@ -0,0 +1,60 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.bukkit.uuid; + +import com.destroystokyo.paper.profile.PlayerProfile; +import com.plotsquared.core.uuid.UUIDMapping; +import com.plotsquared.core.uuid.UUIDService; +import org.bukkit.Bukkit; +import org.checkerframework.checker.nullness.qual.NonNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * UUID service that uses the Paper profile API + */ +public class PaperUUIDService implements UUIDService { + + @Override + public @NonNull List getNames(final @NonNull List uuids) { + final List mappings = new ArrayList<>(uuids.size()); + for (final UUID uuid : uuids) { + final PlayerProfile playerProfile = Bukkit.createProfile(uuid); + if ((playerProfile.isComplete() || playerProfile.completeFromCache()) && playerProfile.getId() != null) { + mappings.add(new UUIDMapping(playerProfile.getId(), playerProfile.getName())); + } + } + return mappings; + } + + @Override + public @NonNull List getUUIDs(final @NonNull List usernames) { + final List mappings = new ArrayList<>(usernames.size()); + for (final String username : usernames) { + final PlayerProfile playerProfile = Bukkit.createProfile(username); + if ((playerProfile.isComplete() || playerProfile.completeFromCache()) && playerProfile.getId() != null) { + mappings.add(new UUIDMapping(playerProfile.getId(), playerProfile.getName())); + } + } + return mappings; + } + +} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SquirrelIdUUIDService.java b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SquirrelIdUUIDService.java new file mode 100644 index 0000000000..58bda3e3ab --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SquirrelIdUUIDService.java @@ -0,0 +1,112 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.bukkit.uuid; + +import com.google.common.util.concurrent.RateLimiter; +import com.plotsquared.core.configuration.Settings; +import com.plotsquared.core.uuid.UUIDMapping; +import com.plotsquared.core.uuid.UUIDService; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.enginehub.squirrelid.Profile; +import org.enginehub.squirrelid.resolver.HttpRepositoryService; +import org.enginehub.squirrelid.resolver.ProfileService; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +/** + * UUID service using SquirrelID + */ +@SuppressWarnings("UnstableApiUsage") +public class SquirrelIdUUIDService implements UUIDService { + + private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + SquirrelIdUUIDService.class.getSimpleName()); + + private final ProfileService profileService; + private final RateLimiter rateLimiter; + + /** + * Create a new SquirrelID UUID service + * + * @param rateLimit Mojangs rate limit is 600 requests per 10 minutes. + * This parameter specifies how many of those requests + * we can use before our internal rate limit kicks in. + */ + public SquirrelIdUUIDService(final int rateLimit) { + this.profileService = HttpRepositoryService.forMinecraft(); + // RateLimiter uses request per seconds. The constructor + // parameter rateLimit is requests per 600 seconds + this.rateLimiter = RateLimiter.create(rateLimit / 600.0D); + } + + @Override + public @NonNull List getNames(final @NonNull List uuids) { + final List results = new ArrayList<>(uuids.size()); + this.rateLimiter.acquire(uuids.size()); + try { + try { + for (final Profile profile : this.profileService.findAllByUuid(uuids)) { + results.add(new UUIDMapping(profile.getUniqueId(), profile.getName())); + } + } catch (final IllegalArgumentException illegalArgumentException) { + // + // This means that the UUID was invalid for whatever reason, we'll try to + // go through them one by one + // + if (uuids.size() >= 2) { + if (Settings.DEBUG) { + LOGGER.info("(UUID) Found invalid UUID in batch. Will try each UUID individually."); + } + for (final UUID uuid : uuids) { + final List result = this.getNames(Collections.singletonList(uuid)); + if (result.isEmpty()) { + continue; + } + results.add(result.get(0)); + } + } else if (uuids.size() == 1 && Settings.DEBUG) { + LOGGER.info("(UUID) Found invalid UUID: {}", uuids.get(0)); + } + } + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } + return results; + } + + @Override + public @NonNull List getUUIDs(final @NonNull List usernames) { + final List results = new ArrayList<>(usernames.size()); + this.rateLimiter.acquire(usernames.size()); + try { + for (final Profile profile : this.profileService.findAllByName(usernames)) { + results.add(new UUIDMapping(profile.getUniqueId(), profile.getName())); + } + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } + return results; + } + +} From bd772a35a52aa28a2cf5ac15082ec8fc981e7237 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sat, 6 Sep 2025 22:28:01 +0200 Subject: [PATCH 093/141] feat: rename RunnableVal variable for clarity in plot creation logic --- Core/src/main/java/com/plotsquared/core/command/Auto.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/command/Auto.java b/Core/src/main/java/com/plotsquared/core/command/Auto.java index 230ed9e3aa..0ca8650d42 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Auto.java +++ b/Core/src/main/java/com/plotsquared/core/command/Auto.java @@ -158,7 +158,7 @@ private void claimSingle( } plot.setOwnerAbs(player.getUUID()); - final RunnableVal runnableVal = new RunnableVal<>() { + final RunnableVal successRunner = new RunnableVal<>() { { this.value = plot; } @@ -176,7 +176,7 @@ public void run(final Plot plot) { } }; - DBFunc.createPlotSafe(plot, runnableVal, () -> claimSingle(player, plot, plotArea, schematic)); + DBFunc.createPlotSafe(plot, successRunner, () -> {}); } From d52e7904e94e81ffd7143361045e946454a436a1 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sat, 6 Sep 2025 22:28:18 +0200 Subject: [PATCH 094/141] feat: simplify H2 database URL construction using switch expression --- .../config/JpaPropertiesProvider.java | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java b/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java index 99cd2712b3..793bb64dae 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java @@ -50,19 +50,11 @@ public Map getProperties() { props.put("jakarta.persistence.jdbc.driver", "com.mysql.cj.jdbc.Driver"); props.put("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect"); } else if (Storage.H2.USE) { - String url; - switch (Storage.H2.MODE.toUpperCase()) { - case "MEMORY": - url = "jdbc:h2:mem:" + Storage.H2.DB; - break; - case "SERVER": - url = "jdbc:h2:tcp://localhost/" + Storage.H2.DB; - break; - case "FILE": - default: - url = "jdbc:h2:file:./" + Storage.H2.DB; - break; - } + String url = switch (Storage.H2.MODE.toUpperCase()) { + case "MEMORY" -> "jdbc:h2:mem:" + Storage.H2.DB; + case "SERVER" -> "jdbc:h2:tcp://localhost/" + Storage.H2.DB; + default -> "jdbc:h2:file:./" + Storage.H2.DB; + }; if (!Storage.H2.PROPERTIES.isEmpty()) { url += ";" + String.join(";", Storage.H2.PROPERTIES); } From 76c6508b6be9134fce08e39e299a156b2809ef8a Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sat, 6 Sep 2025 22:28:29 +0200 Subject: [PATCH 095/141] feat: switch to Hibernate for EntityManagerFactory creation and update data source handling --- .../core/persistence/config/PersistenceModule.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java b/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java index a16d9afd9b..9ae902c6cc 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java @@ -49,7 +49,7 @@ import com.plotsquared.core.persistence.repository.jpa.PlotRatingRepositoryJpa; import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManagerFactory; -import jakarta.persistence.Persistence; +import org.hibernate.jpa.HibernatePersistenceProvider; import javax.sql.DataSource; import java.util.Map; @@ -100,9 +100,11 @@ DataSource provideDataSource(DataSourceProvider dataSourceProvider) { @Provides @Singleton - EntityManagerFactory provideEmf(JpaPropertiesProvider jpaPropertiesProvider) { + EntityManagerFactory provideEmf(JpaPropertiesProvider jpaPropertiesProvider, DataSource ds, LiquibaseBootstrap liquibaseBootstrap) { Map props = jpaPropertiesProvider.getProperties(); - return syncThreadForServiceLoader(() -> Persistence.createEntityManagerFactory("plotsquaredPU", props)); + props.put("jakarta.persistence.nonJtaDataSource", ds); + return syncThreadForServiceLoader(() -> new HibernatePersistenceProvider().createEntityManagerFactory("plotsquaredPU", + props)); } @Provides From cc38465e3bbcd743353cd9d9fd8dce1b3f457e84 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sat, 6 Sep 2025 22:28:34 +0200 Subject: [PATCH 096/141] feat: convert identifiers to uppercase in PrefixedNamingStrategy --- .../core/persistence/config/PrefixedNamingStrategy.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/PrefixedNamingStrategy.java b/Core/src/main/java/com/plotsquared/core/persistence/config/PrefixedNamingStrategy.java index e8075cf42a..d0acdf55b6 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/PrefixedNamingStrategy.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/PrefixedNamingStrategy.java @@ -45,7 +45,7 @@ public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment env) { if (name == null) { return null; } - return Identifier.toIdentifier(prefix + name.getText(), name.isQuoted()); + return Identifier.toIdentifier((prefix + name.getText()).toUpperCase(), name.isQuoted()); } @Override @@ -65,7 +65,7 @@ public Identifier toPhysicalSequenceName(Identifier n, JdbcEnvironment e) { @Override public Identifier toPhysicalColumnName(Identifier n, JdbcEnvironment e) { - return n; + return Identifier.toIdentifier(n.getText().toUpperCase()); } } From 1f38e435d941ea6345b8d882e42f9c56d6ab884e Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sat, 6 Sep 2025 22:28:43 +0200 Subject: [PATCH 097/141] feat: refactor database changelogs for v8 migration and new table creation --- .../db/changelog/db.changelog-master.xml | 3 +- .../db/changelog/v7-to-v8-migration.xml | 16 +- .../changelog/v8.0.0/db.changelog-v8.0.0.xml | 478 +++++++----------- 3 files changed, 177 insertions(+), 320 deletions(-) diff --git a/Core/src/main/resources/db/changelog/db.changelog-master.xml b/Core/src/main/resources/db/changelog/db.changelog-master.xml index 7bfdf6cb3d..3fdc17ff98 100644 --- a/Core/src/main/resources/db/changelog/db.changelog-master.xml +++ b/Core/src/main/resources/db/changelog/db.changelog-master.xml @@ -6,7 +6,7 @@ http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.20.xsd"> - + @@ -14,4 +14,5 @@ + diff --git a/Core/src/main/resources/db/changelog/v7-to-v8-migration.xml b/Core/src/main/resources/db/changelog/v7-to-v8-migration.xml index 1a2270c260..4be5c36a44 100644 --- a/Core/src/main/resources/db/changelog/v7-to-v8-migration.xml +++ b/Core/src/main/resources/db/changelog/v7-to-v8-migration.xml @@ -10,9 +10,7 @@ - - - + Add auto-increment ID column to existing v7 plot table @@ -34,9 +32,7 @@ - - - + Create plot_settings table for v8 @@ -240,9 +236,7 @@ - - - + Add auto-increment meta_id column to existing v7 player_meta table @@ -260,9 +254,7 @@ - - - + Create plot_flags table if missing diff --git a/Core/src/main/resources/db/changelog/v8.0.0/db.changelog-v8.0.0.xml b/Core/src/main/resources/db/changelog/v8.0.0/db.changelog-v8.0.0.xml index 61d09110e5..5c43ac7dad 100644 --- a/Core/src/main/resources/db/changelog/v8.0.0/db.changelog-v8.0.0.xml +++ b/Core/src/main/resources/db/changelog/v8.0.0/db.changelog-v8.0.0.xml @@ -5,233 +5,143 @@ xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.20.xsd"> - - - + + - + - Create plot table for new v8 installations + + + + + + + + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + - - + + - - - - - - - - - - - + + - + - Create plot_settings table for new v8 installations - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - + + - - - - - + + - + - Create plot_flags table for new v8 installations - - - - + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - - - - - - - - - - - + + - + - Create plot membership tables for new v8 installations - - - - - - - - + + + - - - - - + - + - - - - - + - + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + - + - Create plot comments and ratings tables for new v8 installations - - - + - - - - + + + + @@ -241,179 +151,133 @@ + - - + + + + + + + - - - - + - - + + - - - - - - - + + - + - Create player_meta table for new v8 installations - - - - - - - - - - + + + - + + + - - - - - + + - + - Create cluster tables for new v8 installations - - - - - - - - - - - - - - - - - - - - - - - + + + - - + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + - - + + - + + - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - + + + + + + + + + - + + - - + + + - + + + - + + + - - - - - - - - + + From bd7dabfb425c158b6d45ca8698acf65bb5d0c57d Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sat, 6 Sep 2025 22:29:10 +0200 Subject: [PATCH 098/141] feat: add named query to find all plot flags by multiple plot IDs --- .../plotsquared/core/persistence/entity/PlotFlagEntity.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotFlagEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotFlagEntity.java index dec5b9f5ed..e6724b2d16 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotFlagEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotFlagEntity.java @@ -35,12 +35,9 @@ @Table(name = "plot_flags", uniqueConstraints = @UniqueConstraint(columnNames = {"plot_id","flag"})) @NamedQueries({ @NamedQuery(name = "PlotFlag.findByPlot", query = "SELECT f FROM PlotFlagEntity f WHERE f.plot.id = :plotId"), + @NamedQuery(name = "PlotFlag.findAllInPlotIds", query = "SELECT f FROM PlotFlagEntity f WHERE f.plot.id IN :plotIds"), @NamedQuery(name = "PlotFlag.findByPlotAndName", query = "SELECT f FROM PlotFlagEntity f WHERE f.plot.id = :plotId AND f.flag = :flag"), - @NamedQuery(name = "PlotFlag.deleteByPlotAndName", query = "DELETE FROM PlotFlagEntity f WHERE f.plot.id = :plotId AND " + - "f.flag = :flag"), - @NamedQuery(name = "PlotFlag.deleteByPlot", query = "DELETE FROM PlotFlagEntity f WHERE f.plot.id = :plotId"), @NamedQuery(name = "PlotFlag.findAll", query = "SELECT f FROM PlotFlagEntity f"), - @NamedQuery(name = "PlotFlag.deleteAllInPlotIds", query = "DELETE FROM PlotFlagEntity f WHERE f.plot.id IN :plotIds") }) public class PlotFlagEntity { @Id From 065be17535f8a3c847e5daa61185f6891285a82c Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sat, 6 Sep 2025 22:29:14 +0200 Subject: [PATCH 099/141] feat: update PlotFlag repository methods to use getSingleResultOrNull and improve deletion logic --- .../repository/jpa/PlotFlagRepositoryJpa.java | 11 +++++++---- .../persistence/repository/jpa/PlotRepositoryJpa.java | 10 +++++----- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotFlagRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotFlagRepositoryJpa.java index 701f4556b8..d2de387eef 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotFlagRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotFlagRepositoryJpa.java @@ -55,10 +55,10 @@ public PlotFlagRepositoryJpa(EntityManagerFactory emf) { @Override public @NotNull Optional findByPlotAndName(long plotId, @NotNull String flagName) { try (EntityManager em = emf.createEntityManager()) { - return em.createNamedQuery("PlotFlag.findByPlotAndName", PlotFlagEntity.class) + return Optional.ofNullable(em.createNamedQuery("PlotFlag.findByPlotAndName", PlotFlagEntity.class) .setParameter("plotId", plotId) .setParameter("flag", flagName) - .getResultStream().findFirst(); + .getSingleResultOrNull()); } } @@ -97,10 +97,13 @@ public void deleteByPlotAndName(long plotId, @NotNull String flagName) { EntityTransaction tx = em.getTransaction(); try (em) { tx.begin(); - em.createNamedQuery("PlotFlag.deleteByPlotAndName") + var plot = em.createNamedQuery("PlotFlag.findByPlotAndName", PlotFlagEntity.class) .setParameter("plotId", plotId) .setParameter("flag", flagName) - .executeUpdate(); + .getSingleResultOrNull(); + if (plot != null) { + em.remove(plot); + } tx.commit(); } catch (RuntimeException e) { if (tx.isActive()) tx.rollback(); diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java index 06a8fcaedd..dd5b0da647 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java @@ -363,7 +363,7 @@ public void setOwner(final @NotNull Plot plot, final @NotNull UUID newOwner) { .setParameter("world", plot.getWorldName()) .setParameter("x", plot.getId().getX()) .setParameter("z", plot.getId().getY()) - .setParameter("owner", newOwner); + .setParameter("owner", newOwner.toString()); tx.commit(); } catch (RuntimeException e) { if (tx.isActive()) { @@ -521,9 +521,9 @@ public void delete(final Plot plot) { if (pe != null && pe.getId() != null) { Long plotId = pe.getId(); // Delete children first to satisfy FK constraints - em.createNamedQuery("PlotFlag.deleteByPlot") + em.createNamedQuery("PlotFlag.findByPlot") .setParameter("plotId", plotId) - .executeUpdate(); + .getResultList().forEach(em::remove); em.createNamedQuery("PlotHelper.deleteByPlotId") .setParameter("plotId", plotId) .executeUpdate(); @@ -710,9 +710,9 @@ public void purgeIds(@NotNull Set ids) { return; } // Delete child tables first - em.createNamedQuery("PlotFlag.deleteAllInPlotIds") + em.createNamedQuery("PlotFlag.findAllInPlotIds") .setParameter("plotIds", longIds) - .executeUpdate(); + .getResultList().forEach(em::remove); em.createNamedQuery("PlotTrusted.deleteAllInPlotIds") .setParameter("plotIds", longIds) .executeUpdate(); From 07b0b1447305cd10ea005efadb2b31918f2f9de6 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sat, 6 Sep 2025 22:52:36 +0200 Subject: [PATCH 100/141] feat: update PlayerMetaEntity and PlotFlagEntity to use more descriptive value methods --- .../src/main/java/com/plotsquared/core/database/DBFunc.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java index bed13cdc35..79bf82896c 100644 --- a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java +++ b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java @@ -80,7 +80,7 @@ public static void getPersistentMeta(UUID uuid, RunnableVal> PlayerMetaRepository repo = PlotSquared.platform().injector().getInstance(PlayerMetaRepository.class); Map map = new HashMap<>(); for (PlayerMetaEntity e : repo.findByUuid(uuid.toString())) { - map.put(e.getKey(), e.getValue()); + map.put(e.getKey(), e.getPlayerMetaValue()); } if (result != null) { result.run(map); @@ -317,7 +317,7 @@ public static void setFlag(Plot plot, PlotFlag flag) { var existing = flagRepo.findByPlotAndName(plotId, name); if (existing.isPresent()) { var e = existing.get(); - e.setValue(value); + e.setFlagValue(value); flagRepo.save(e); } else { PlotFlagEntity e = new PlotFlagEntity(); @@ -325,7 +325,7 @@ public static void setFlag(Plot plot, PlotFlag flag) { pref.setId(entity.getId()); e.setPlot(pref); e.setFlag(name); - e.setValue(value); + e.setFlagValue(value); flagRepo.save(e); } }); From e3b146583f620ff572e762e309716028ea7459e2 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sat, 6 Sep 2025 22:52:55 +0200 Subject: [PATCH 101/141] feat: enhance PrefixedNamingStrategy to handle null identifiers and convert names to uppercase --- .../config/PrefixedNamingStrategy.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/PrefixedNamingStrategy.java b/Core/src/main/java/com/plotsquared/core/persistence/config/PrefixedNamingStrategy.java index d0acdf55b6..d7f4b2c403 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/PrefixedNamingStrategy.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/PrefixedNamingStrategy.java @@ -50,21 +50,33 @@ public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment env) { @Override public Identifier toPhysicalCatalogName(Identifier n, JdbcEnvironment e) { - return n; + if (n == null) { + return null; + } + return Identifier.toIdentifier(n.getText().toUpperCase()); } @Override public Identifier toPhysicalSchemaName(Identifier n, JdbcEnvironment e) { - return n; + if (n == null) { + return null; + } + return Identifier.toIdentifier(n.getText().toUpperCase()); } @Override public Identifier toPhysicalSequenceName(Identifier n, JdbcEnvironment e) { - return n; + if (n == null) { + return null; + } + return Identifier.toIdentifier(n.getText().toUpperCase()); } @Override public Identifier toPhysicalColumnName(Identifier n, JdbcEnvironment e) { + if (n == null) { + return null; + } return Identifier.toIdentifier(n.getText().toUpperCase()); } From e109c304e93b18ccd4bfe2f78418a8afd550b6cd Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sat, 6 Sep 2025 22:53:05 +0200 Subject: [PATCH 102/141] feat: rename fields in PlayerMetaEntity and PlotFlagEntity for clarity --- .../core/persistence/entity/PlayerMetaEntity.java | 10 +++++----- .../core/persistence/entity/PlotFlagEntity.java | 15 +++++++++------ 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlayerMetaEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlayerMetaEntity.java index a0b4e36e68..9c6e7b7ace 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlayerMetaEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlayerMetaEntity.java @@ -41,11 +41,11 @@ public class PlayerMetaEntity { private Long id; @Column(length = 40, nullable = false) private String uuid; - @Column(name = "key", length = 32, nullable = false) + @Column(name = "playerMetaKey", length = 32, nullable = false) private String key; @Lob - @Column(name = "value", nullable = false) - private byte[] value; + @Column(name = "playerMetaValue", nullable = false) + private byte[] playerMetaValue; public PlayerMetaEntity() {} @@ -55,6 +55,6 @@ public PlayerMetaEntity() {} public void setUuid(String uuid) { this.uuid = uuid; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } - public byte[] getValue() { return value; } - public void setValue(byte[] value) { this.value = value; } + public byte[] getPlayerMetaValue() { return playerMetaValue; } + public void setPlayerMetaValue(byte[] value) { this.playerMetaValue = value; } } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotFlagEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotFlagEntity.java index e6724b2d16..373195b1e4 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotFlagEntity.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotFlagEntity.java @@ -34,9 +34,12 @@ @Entity @Table(name = "plot_flags", uniqueConstraints = @UniqueConstraint(columnNames = {"plot_id","flag"})) @NamedQueries({ - @NamedQuery(name = "PlotFlag.findByPlot", query = "SELECT f FROM PlotFlagEntity f WHERE f.plot.id = :plotId"), - @NamedQuery(name = "PlotFlag.findAllInPlotIds", query = "SELECT f FROM PlotFlagEntity f WHERE f.plot.id IN :plotIds"), - @NamedQuery(name = "PlotFlag.findByPlotAndName", query = "SELECT f FROM PlotFlagEntity f WHERE f.plot.id = :plotId AND f.flag = :flag"), + @NamedQuery(name = "PlotFlag.findByPlot", query = "SELECT f FROM PlotFlagEntity f join fetch f.plot p WHERE p.id =" + + " " + + ":plotId"), + @NamedQuery(name = "PlotFlag.findAllInPlotIds", query = "SELECT f FROM PlotFlagEntity f join fetch f.plot p WHERE p.id IN :plotIds"), + @NamedQuery(name = "PlotFlag.findByPlotAndName", query = "SELECT f FROM PlotFlagEntity f join fetch f.plot p WHERE p.id" + + " = :plotId AND f.flag = :flag"), @NamedQuery(name = "PlotFlag.findAll", query = "SELECT f FROM PlotFlagEntity f"), }) public class PlotFlagEntity { @@ -49,7 +52,7 @@ public class PlotFlagEntity { @Column(length = 64) private String flag; @Column(length = 512) - private String value; + private String flagValue; public PlotFlagEntity() {} @@ -62,6 +65,6 @@ public PlotFlagEntity() {} public String getFlag() { return flag; } public void setFlag(String flag) { this.flag = flag; } - public String getValue() { return value; } - public void setValue(String value) { this.value = value; } + public String getFlagValue() { return flagValue; } + public void setFlagValue(String value) { this.flagValue = value; } } From 1c9dc4e103d641ae5c31d552bcc36b9d9dad04c9 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sat, 6 Sep 2025 22:53:12 +0200 Subject: [PATCH 103/141] feat: update PlayerMetaEntity and PlotFlagEntity to use more descriptive value methods --- .../persistence/repository/jpa/PlayerMetaRepositoryJpa.java | 2 +- .../core/persistence/repository/jpa/PlotRepositoryJpa.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlayerMetaRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlayerMetaRepositoryJpa.java index d3825491a1..a89804fa23 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlayerMetaRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlayerMetaRepositoryJpa.java @@ -64,7 +64,7 @@ public void put(@NotNull String uuid, @NotNull String key, byte @NotNull [] valu PlayerMetaEntity e = new PlayerMetaEntity(); e.setUuid(uuid); e.setKey(key); - e.setValue(value); + e.setPlayerMetaValue(value); em.persist(e); tx.commit(); } catch (RuntimeException ex) { diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java index dd5b0da647..dd7c76de4e 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java @@ -195,7 +195,7 @@ public void createPlotsAndData(final List plots) { PlotFlagEntity fe = new PlotFlagEntity(); fe.setPlot(pe); fe.setFlag(flagEntry.getName()); - fe.setValue(flagEntry.toString()); + fe.setFlagValue(flagEntry.toString()); em.persist(fe); } } @@ -647,7 +647,7 @@ public HashMap> getPlots() { var plot = byId.get(f.getPlot().getId()); if (plot != null) { String flag = f.getFlag(); - String value = f.getValue(); + String value = f.getFlagValue(); var registry = com.plotsquared.core.plot.flag.GlobalFlagContainer.getInstance(); var plotFlag = registry.getFlagFromString(flag); if (plotFlag == null) { From 3317b2e4d05971789a0999781da7c7021ea3c170 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sat, 6 Sep 2025 22:53:16 +0200 Subject: [PATCH 104/141] feat: rename columns in database schema for PlayerMetaEntity and PlotFlagEntity for clarity --- .../resources/db/changelog/v8.0.0/db.changelog-v8.0.0.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/main/resources/db/changelog/v8.0.0/db.changelog-v8.0.0.xml b/Core/src/main/resources/db/changelog/v8.0.0/db.changelog-v8.0.0.xml index 5c43ac7dad..61767cb2f9 100644 --- a/Core/src/main/resources/db/changelog/v8.0.0/db.changelog-v8.0.0.xml +++ b/Core/src/main/resources/db/changelog/v8.0.0/db.changelog-v8.0.0.xml @@ -90,10 +90,10 @@ - + - + @@ -183,7 +183,7 @@ - + From d5c3185faadb3d87b839ff5ae2b7703fcad12c7a Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sat, 6 Sep 2025 22:53:42 +0200 Subject: [PATCH 105/141] feat: remove unused imports from BukkitPlatform.java for cleaner code --- .../main/java/com/plotsquared/bukkit/BukkitPlatform.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java index 4dea647b3f..9c8550f494 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java @@ -99,7 +99,6 @@ import com.plotsquared.core.setup.PlotAreaBuilder; import com.plotsquared.core.setup.SettingsNodesWrapper; import com.plotsquared.core.util.EventDispatcher; -import com.plotsquared.core.util.FileUtils; import com.plotsquared.core.util.PlatformWorldManager; import com.plotsquared.core.util.PlayerManager; import com.plotsquared.core.util.PremiumVerification; @@ -149,18 +148,10 @@ import java.util.Collections; import java.util.Comparator; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Queue; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executors; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; import static com.plotsquared.core.util.PremiumVerification.getDownloadID; import static com.plotsquared.core.util.PremiumVerification.getResourceID; From b90a20b1438744c486811883cacf04376be0674c Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sat, 6 Sep 2025 22:53:48 +0200 Subject: [PATCH 106/141] feat: remove trailing whitespace in Storage.java for cleaner code --- .../main/java/com/plotsquared/core/configuration/Storage.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/src/main/java/com/plotsquared/core/configuration/Storage.java b/Core/src/main/java/com/plotsquared/core/configuration/Storage.java index 9647965a9a..43698152e2 100644 --- a/Core/src/main/java/com/plotsquared/core/configuration/Storage.java +++ b/Core/src/main/java/com/plotsquared/core/configuration/Storage.java @@ -76,4 +76,3 @@ public static final class H2 { } } - From 0667ba763145ba4cef4b0fa7d63ba5b7bb85888f Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sat, 6 Sep 2025 22:53:52 +0200 Subject: [PATCH 107/141] feat: remove unused Logger import from DatabaseMigrationService.java for cleaner code --- .../core/persistence/config/DatabaseMigrationService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/DatabaseMigrationService.java b/Core/src/main/java/com/plotsquared/core/persistence/config/DatabaseMigrationService.java index 926f49bacf..878f2f192d 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/DatabaseMigrationService.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/DatabaseMigrationService.java @@ -25,7 +25,6 @@ import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.logging.Logger; /** * Service for providing database information and status. From 86cd252337865d9b6614fe27cfee91568961991f Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sat, 6 Sep 2025 22:53:56 +0200 Subject: [PATCH 108/141] feat: remove unused Logger import from DataSourceProvider.java for cleaner code --- .../plotsquared/core/persistence/config/DataSourceProvider.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/DataSourceProvider.java b/Core/src/main/java/com/plotsquared/core/persistence/config/DataSourceProvider.java index 5092d0802d..568fc33c0f 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/DataSourceProvider.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/DataSourceProvider.java @@ -24,7 +24,6 @@ import com.zaxxer.hikari.HikariDataSource; import javax.sql.DataSource; -import java.util.logging.Logger; /** * Provides configured DataSource instances for database connections. From aeb23cffa16173b17445c5222c58e98bb29a6d50 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sat, 6 Sep 2025 22:54:02 +0200 Subject: [PATCH 109/141] feat: add license header to InstallationState.java for compliance --- .../persistence/config/InstallationState.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/InstallationState.java b/Core/src/main/java/com/plotsquared/core/persistence/config/InstallationState.java index b33d61b6d6..7db02a3592 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/InstallationState.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/InstallationState.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.persistence.config; enum InstallationState { From 8c30f89888c52045ad0644735886ace0a72b3433 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sat, 6 Sep 2025 23:28:58 +0200 Subject: [PATCH 110/141] feat: remove logging of database version in LiquibaseBootstrap for cleaner migration process --- .../core/persistence/config/LiquibaseBootstrap.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseBootstrap.java b/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseBootstrap.java index 33f806fe04..7bd4dc7675 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseBootstrap.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseBootstrap.java @@ -52,13 +52,6 @@ public LiquibaseBootstrap(DataSource dataSource, DatabaseMigrationService migrat try (Connection connection = dataSource.getConnection()) { Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection)); - // Log database version information - InstallationState installationState = migrationService.getDatabaseVersion(connection); - LOGGER.info("Detected database version: " + installationState.getDescription()); - if (installationState == InstallationState.UPGRADE_FROM_V7) { - liquibaseCrossDatabaseMigrationService.migrateToH2(); - } - // Run Liquibase migrations - this will handle both v7->v8 migration and new v8 installations Liquibase liquibase = new Liquibase("db/changelog/db.changelog-master.xml", new ClassLoaderResourceAccessor(), database); From f24b6172892983da73919b529ae4ab90d836b7eb Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sat, 6 Sep 2025 23:47:11 +0200 Subject: [PATCH 111/141] feat: simplify LiquibaseBootstrap and remove unused migration validation logic for cleaner code --- .../config/DatabaseMigrationService.java | 92 ------------------- .../config/LiquibaseBootstrap.java | 3 +- ...iquibaseCrossDatabaseMigrationService.java | 51 +--------- .../persistence/config/PersistenceModule.java | 1 - 4 files changed, 3 insertions(+), 144 deletions(-) delete mode 100644 Core/src/main/java/com/plotsquared/core/persistence/config/DatabaseMigrationService.java diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/DatabaseMigrationService.java b/Core/src/main/java/com/plotsquared/core/persistence/config/DatabaseMigrationService.java deleted file mode 100644 index 878f2f192d..0000000000 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/DatabaseMigrationService.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.core.persistence.config; - -import com.google.inject.Singleton; -import com.plotsquared.core.configuration.Storage; - -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.ResultSet; -import java.sql.SQLException; - -/** - * Service for providing database information and status. - * All database migrations are now handled completely by Liquibase. - * - * @since 8.0.0 - * @version 1.0.0 - * @author TheMeinerLP - * @author IntellectualSites - */ -@Singleton -public final class DatabaseMigrationService { - - /** - * Checks if the current database is using the v7 schema format. - * This is used for informational purposes since Liquibase handles the migration automatically. - */ - public boolean isV7Database(Connection connection) throws SQLException { - String prefix = Storage.PREFIX == null ? "" : Storage.PREFIX; - DatabaseMetaData metaData = connection.getMetaData(); - - try (ResultSet tables = metaData.getTables(null, null, prefix + "plot", new String[]{"TABLE"})) { - if (!tables.next()) { - // No plot table exists, assume new installation - return false; - } - } - - // Check if the plot table has v7 structure (no auto-increment ID column) - try (ResultSet columns = metaData.getColumns(null, null, prefix + "plot", null)) { - boolean hasIdColumn = false; - boolean hasV7Columns = false; - - while (columns.next()) { - String columnName = columns.getString("COLUMN_NAME"); - if ("id".equalsIgnoreCase(columnName)) { - hasIdColumn = true; - } - if ("plot_id_x".equalsIgnoreCase(columnName) || "plot_id_z".equalsIgnoreCase(columnName)) { - hasV7Columns = true; - } - } - - // v7 has plot_id_x/plot_id_z but no auto-increment ID column - // v8 has both the coordinates AND an auto-increment ID column - return hasV7Columns && !hasIdColumn; - } - } - - /** - * Gets the current database version information. - */ - public InstallationState getDatabaseVersion(Connection connection) throws SQLException { - if (!isV7Database(connection)) { - String prefix = Storage.PREFIX == null ? "" : Storage.PREFIX; - try (ResultSet tables = connection.getMetaData().getTables(null, null, prefix + "plot", new String[]{"TABLE"})) { - if (!tables.next()) { - return InstallationState.FRESH_INSTALLATION; - } - } - return InstallationState.NO_MIGRATION_NEEDED; - } - return InstallationState.UPGRADE_FROM_V7; - } -} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseBootstrap.java b/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseBootstrap.java index 7bd4dc7675..f63fa342a7 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseBootstrap.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseBootstrap.java @@ -46,8 +46,7 @@ public final class LiquibaseBootstrap { private static final Logger LOGGER = Logger.getLogger(LiquibaseBootstrap.class.getName()); @Inject - public LiquibaseBootstrap(DataSource dataSource, DatabaseMigrationService migrationService, - LiquibaseCrossDatabaseMigrationService liquibaseCrossDatabaseMigrationService) { + public LiquibaseBootstrap(DataSource dataSource) { syncThreadForServiceLoader(() -> { try (Connection connection = dataSource.getConnection()) { Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection)); diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseCrossDatabaseMigrationService.java b/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseCrossDatabaseMigrationService.java index f0eeb7425f..b5f1c32860 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseCrossDatabaseMigrationService.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseCrossDatabaseMigrationService.java @@ -175,19 +175,8 @@ private void migrateUsingLiquibaseNative(DataSource sourceDataSource, DataSource * Generates a Liquibase changelog with data using Liquibase's native capabilities. */ private void generateDataChangeLog(Database sourceDatabase, Path outputFile) throws Exception { - try (PrintStream output = new PrintStream(Files.newOutputStream(outputFile))) { - - // Create Liquibase instance - Liquibase liquibase = new Liquibase("", new ClassLoaderResourceAccessor(), sourceDatabase); - - // Generate changelog including data - // This uses Liquibase's built-in generateChangeLog with data option - generateChangeLogUsingDiff(sourceDatabase, sourceDatabase, outputFile); - - } catch (Exception e) { - LOGGER.severe("Failed to generate data changelog: " + e.getMessage()); - throw e; - } + // This uses Liquibase's built-in generateChangeLog with data option + generateChangeLogUsingDiff(sourceDatabase, sourceDatabase, outputFile); } /** @@ -215,40 +204,4 @@ private void generateChangeLogUsingDiff(Database sourceDatabase, Database target throw e; } } - - /** - * Validates that the migration was successful by comparing database structures. - */ - public boolean validateMigration(DataSource sourceDataSource, DataSource targetDataSource) { - try (Connection sourceConnection = sourceDataSource.getConnection(); - Connection targetConnection = targetDataSource.getConnection()) { - - Database sourceDatabase = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(sourceConnection)); - Database targetDatabase = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(targetConnection)); - - // Create snapshots of both databases - DatabaseSnapshot sourceSnapshot = liquibase.snapshot.SnapshotGeneratorFactory.getInstance() - .createSnapshot(sourceDatabase.getDefaultSchema(), sourceDatabase, new liquibase.snapshot.SnapshotControl(sourceDatabase)); - - DatabaseSnapshot targetSnapshot = liquibase.snapshot.SnapshotGeneratorFactory.getInstance() - .createSnapshot(targetDatabase.getDefaultSchema(), targetDatabase, new liquibase.snapshot.SnapshotControl(targetDatabase)); - - // Compare structure and data - DiffResult diffResult = DiffGeneratorFactory.getInstance().compare(sourceSnapshot, targetSnapshot, new CompareControl()); - - boolean hasUnexpectedDiffs = !diffResult.areEqual(); - - if (!hasUnexpectedDiffs) { - LOGGER.info("Migration validation successful: Databases are identical"); - } else { - LOGGER.warning("Migration validation found differences between source and target databases"); - } - - return !hasUnexpectedDiffs; - - } catch (Exception e) { - LOGGER.severe("Error during migration validation: " + e.getMessage()); - return false; - } - } } diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java b/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java index 9ae902c6cc..ed124dca2c 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java @@ -85,7 +85,6 @@ protected void configure() { // Bind configuration and migration services bind(JpaPropertiesProvider.class).asEagerSingleton(); bind(DataSourceProvider.class).asEagerSingleton(); - bind(DatabaseMigrationService.class).asEagerSingleton(); bind(LiquibaseCrossDatabaseMigrationService.class).asEagerSingleton(); // Eagerly run Liquibase migrations on startup From 7981a6e7acabe73032edc2367169cd497d07f5f5 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 00:04:19 +0200 Subject: [PATCH 112/141] feat: make PrefixedNamingStrategy class final for better immutability --- .../core/persistence/config/PrefixedNamingStrategy.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/PrefixedNamingStrategy.java b/Core/src/main/java/com/plotsquared/core/persistence/config/PrefixedNamingStrategy.java index d7f4b2c403..ebfed8e74d 100644 --- a/Core/src/main/java/com/plotsquared/core/persistence/config/PrefixedNamingStrategy.java +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/PrefixedNamingStrategy.java @@ -32,7 +32,7 @@ * @author TheMeinerLP * @author IntellectualSites */ -public class PrefixedNamingStrategy implements PhysicalNamingStrategy { +public final class PrefixedNamingStrategy implements PhysicalNamingStrategy { private final String prefix; From 11fb49e903dad9cc48228d9182f995d23e5b42ff Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 00:04:29 +0200 Subject: [PATCH 113/141] feat: add PlayerMetaService interface for managing player metadata --- .../core/services/api/PlayerMetaService.java | 23 +++++++++++++++++++ .../core/services/api/package-info.java | 12 ++++++++++ 2 files changed, 35 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/services/api/PlayerMetaService.java create mode 100644 Core/src/main/java/com/plotsquared/core/services/api/package-info.java diff --git a/Core/src/main/java/com/plotsquared/core/services/api/PlayerMetaService.java b/Core/src/main/java/com/plotsquared/core/services/api/PlayerMetaService.java new file mode 100644 index 0000000000..ff8fc0329d --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/api/PlayerMetaService.java @@ -0,0 +1,23 @@ +package com.plotsquared.core.services.api; + +import java.util.Map; +import java.util.UUID; +import java.util.function.Consumer; + +/** + * Manages player metadata + * + * @version 1.0.0 + * @since 8.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +public interface PlayerMetaService { + + void addPersistentMeta(UUID uuid, String key, byte[] meta, boolean delete); + + void getPersistentMeta(UUID uuid, Consumer> result); + + void removePersistentMeta(UUID uuid, String key); + +} diff --git a/Core/src/main/java/com/plotsquared/core/services/api/package-info.java b/Core/src/main/java/com/plotsquared/core/services/api/package-info.java new file mode 100644 index 0000000000..7821dbd4bf --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/api/package-info.java @@ -0,0 +1,12 @@ +/** + * This package contains interfaces for various services provided by PlotSquared. + * + * @version 1.0.0 + * @since 8.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +@NotNullByDefault +package com.plotsquared.core.services.api; + +import org.jetbrains.annotations.NotNullByDefault; From 27e841dcddcc57c85acefb0faa50b717944a082d Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 00:04:35 +0200 Subject: [PATCH 114/141] feat: implement PlayerMetaDefaultService for managing player metadata --- .../impl/PlayerMetaDefaultService.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/services/impl/PlayerMetaDefaultService.java diff --git a/Core/src/main/java/com/plotsquared/core/services/impl/PlayerMetaDefaultService.java b/Core/src/main/java/com/plotsquared/core/services/impl/PlayerMetaDefaultService.java new file mode 100644 index 0000000000..23346c3fd2 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/impl/PlayerMetaDefaultService.java @@ -0,0 +1,47 @@ +package com.plotsquared.core.services.impl; + +import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.persistence.entity.PlayerMetaEntity; +import com.plotsquared.core.persistence.repository.api.PlayerMetaRepository; +import com.plotsquared.core.services.api.PlayerMetaService; +import jakarta.inject.Inject; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.function.Consumer; + +public class PlayerMetaDefaultService implements PlayerMetaService { + + private final PlayerMetaRepository repository; + + @Inject + public PlayerMetaDefaultService(final PlayerMetaRepository repository) { + this.repository = repository; + } + + @Override + public void addPersistentMeta(final @NotNull UUID uuid, final @NotNull String key, final byte @NotNull [] meta, final boolean delete) { + if (delete) { + this.repository.delete(uuid.toString(), key); + } else { + this.repository.put(uuid.toString(), key, meta); + } + } + + @Override + public void getPersistentMeta(final @NotNull UUID uuid, final @NotNull Consumer> result) { + Map map = new HashMap<>(); + for (PlayerMetaEntity e : this.repository.findByUuid(uuid.toString())) { + map.put(e.getKey(), e.getPlayerMetaValue()); + } + result.accept(map); + } + + @Override + public void removePersistentMeta(final UUID uuid, final @NotNull String key) { + this.repository.delete(uuid.toString(), key); + } + +} From 6411a0060d777418f5cbef522b9a9fd21fd25b7a Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 00:04:39 +0200 Subject: [PATCH 115/141] feat: add ServiceModule for binding PlayerMetaService to PlayerMetaDefaultService --- .../core/services/config/ServiceModule.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java diff --git a/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java b/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java new file mode 100644 index 0000000000..d907a5e5cf --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java @@ -0,0 +1,14 @@ +package com.plotsquared.core.services.config; + +import com.google.inject.AbstractModule; +import com.plotsquared.core.services.api.PlayerMetaService; +import com.plotsquared.core.services.impl.PlayerMetaDefaultService; + +public class ServiceModule extends AbstractModule { + + @Override + protected void configure() { + bind(PlayerMetaService.class).to(PlayerMetaDefaultService.class); + } + +} From 0df99def8aec4ceb795d56b19a6bb3b943b2d9d1 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 00:04:44 +0200 Subject: [PATCH 116/141] feat: add ServiceModule to BukkitPlatform for improved service management --- .../src/main/java/com/plotsquared/bukkit/BukkitPlatform.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java index 9c8550f494..c94925f26d 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java @@ -96,6 +96,7 @@ import com.plotsquared.core.plot.world.PlotAreaManager; import com.plotsquared.core.plot.world.SinglePlotArea; import com.plotsquared.core.plot.world.SinglePlotAreaManager; +import com.plotsquared.core.services.config.ServiceModule; import com.plotsquared.core.setup.PlotAreaBuilder; import com.plotsquared.core.setup.SettingsNodesWrapper; import com.plotsquared.core.util.EventDispatcher; @@ -290,7 +291,8 @@ public void onEnable() { new PlotSquaredModule(), new BukkitModule(this), new BackupModule(), - new PersistenceModule() + new PersistenceModule(), + new ServiceModule() ); this.injector.injectMembers(this); From 5f509ded732f0c0f3382efbbb879cb886e215d4d Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 00:05:01 +0200 Subject: [PATCH 117/141] feat: refactor persistent metadata handling to use PlayerMetaService --- .../com/plotsquared/core/command/Grant.java | 67 ++++---- .../plotsquared/core/player/PlotPlayer.java | 151 +++++++++--------- 2 files changed, 113 insertions(+), 105 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/command/Grant.java b/Core/src/main/java/com/plotsquared/core/command/Grant.java index 18db0c77dc..0531733bd6 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Grant.java +++ b/Core/src/main/java/com/plotsquared/core/command/Grant.java @@ -23,9 +23,11 @@ import com.plotsquared.core.configuration.caption.TranslatableCaption; import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.permissions.Permission; +import com.plotsquared.core.persistence.repository.api.PlayerMetaRepository; import com.plotsquared.core.player.MetaDataAccess; import com.plotsquared.core.player.PlayerMetaDataKeys; import com.plotsquared.core.player.PlotPlayer; +import com.plotsquared.core.services.api.PlayerMetaService; import com.plotsquared.core.util.PlayerManager; import com.plotsquared.core.util.TabCompletions; import com.plotsquared.core.util.task.RunnableVal; @@ -43,6 +45,7 @@ import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeoutException; +import java.util.function.Consumer; import java.util.stream.Collectors; @CommandDeclaration(command = "grant", @@ -108,39 +111,41 @@ public CompletableFuture execute( } } } else { - DBFunc.getPersistentMeta(uuid, new RunnableVal<>() { - @Override - public void run(Map value) { - final byte[] array = value.get("grantedPlots"); - if (arg0.equals("check")) { // check - int granted; - if (array == null) { - granted = 0; - } else { - granted = Ints.fromByteArray(array); - } - player.sendMessage( - TranslatableCaption.of("grants.granted_plots"), - TagResolver.resolver("amount", Tag.inserting(Component.text(granted))) - ); - } else { // add - int amount; - if (array == null) { - amount = 1; - } else { - amount = 1 + Ints.fromByteArray(array); - } - boolean replace = array != null; - String key = "grantedPlots"; - byte[] rawData = Ints.toByteArray(amount); - DBFunc.addPersistentMeta(uuid, key, rawData, replace); - player.sendMessage( - TranslatableCaption.of("grants.added"), - TagResolver.resolver("grants", Tag.inserting(Component.text(amount))) - ); + Consumer> resultConsumer = (value) -> { + final byte[] array = value.get("grantedPlots"); + if (arg0.equals("check")) { // check + int granted; + if (array == null) { + granted = 0; + } else { + granted = Ints.fromByteArray(array); } + player.sendMessage( + TranslatableCaption.of("grants.granted_plots"), + TagResolver.resolver("amount", Tag.inserting(Component.text(granted))) + ); + } else { // add + int amount; + if (array == null) { + amount = 1; + } else { + amount = 1 + Ints.fromByteArray(array); + } + boolean delete = array != null; + String key = "grantedPlots"; + byte[] rawData = Ints.toByteArray(amount); + PlayerMetaService service = + PlotSquared.platform().injector().getInstance(PlayerMetaService.class); + service.addPersistentMeta(uuid, key, rawData, delete); + player.sendMessage( + TranslatableCaption.of("grants.added"), + TagResolver.resolver("grants", Tag.inserting(Component.text(amount))) + ); } - }); + }; + PlayerMetaService service = + PlotSquared.platform().injector().getInstance(PlayerMetaService.class); + service.getPersistentMeta(uuid, resultConsumer); } } }); diff --git a/Core/src/main/java/com/plotsquared/core/player/PlotPlayer.java b/Core/src/main/java/com/plotsquared/core/player/PlotPlayer.java index b0692aa2f1..9b2f6ec19f 100644 --- a/Core/src/main/java/com/plotsquared/core/player/PlotPlayer.java +++ b/Core/src/main/java/com/plotsquared/core/player/PlotPlayer.java @@ -31,7 +31,6 @@ import com.plotsquared.core.configuration.caption.CaptionUtility; import com.plotsquared.core.configuration.caption.LocaleHolder; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.events.TeleportCause; import com.plotsquared.core.location.Location; import com.plotsquared.core.permissions.NullPermissionProfile; @@ -46,10 +45,10 @@ import com.plotsquared.core.plot.world.PlotAreaManager; import com.plotsquared.core.plot.world.SinglePlotArea; import com.plotsquared.core.plot.world.SinglePlotAreaManager; +import com.plotsquared.core.services.api.PlayerMetaService; import com.plotsquared.core.synchronization.LockRepository; import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.query.PlotQuery; -import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.TaskManager; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.world.gamemode.GameMode; @@ -83,6 +82,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; /** * The abstract class supporting {@code BukkitPlayer} and {@code SpongePlayer}. @@ -683,88 +683,87 @@ public Set getPlots(String world) { public void populatePersistentMetaMap() { if (Settings.Enabled_Components.PERSISTENT_META) { - DBFunc.getPersistentMeta(getUUID(), new RunnableVal<>() { - @Override - public void run(Map value) { - try { - PlotPlayer.this.metaMap = value; - if (value.isEmpty()) { - return; - } + PlayerMetaService service = + PlotSquared.platform().injector().getInstance(PlayerMetaService.class); + Consumer> resultConsumer = value -> { + try { + PlotPlayer.this.metaMap = value; + if (value.isEmpty()) { + return; + } - if (PlotPlayer.this.getAttribute("debug")) { - debugModeEnabled.add(PlotPlayer.this); - } + if (PlotPlayer.this.getAttribute("debug")) { + debugModeEnabled.add(PlotPlayer.this); + } - if (!Settings.Teleport.ON_LOGIN) { - return; - } - PlotAreaManager manager = PlotPlayer.this.plotAreaManager; + if (!Settings.Teleport.ON_LOGIN) { + return; + } + PlotAreaManager manager = PlotPlayer.this.plotAreaManager; - if (!(manager instanceof SinglePlotAreaManager)) { - return; - } - PlotArea area = ((SinglePlotAreaManager) manager).getArea(); - boolean V2 = false; - byte[] arr = PlotPlayer.this.getPersistentMeta("quitLoc"); + if (!(manager instanceof SinglePlotAreaManager)) { + return; + } + PlotArea area = ((SinglePlotAreaManager) manager).getArea(); + boolean V2 = false; + byte[] arr = PlotPlayer.this.getPersistentMeta("quitLoc"); + if (arr == null) { + arr = PlotPlayer.this.getPersistentMeta("quitLocV2"); if (arr == null) { - arr = PlotPlayer.this.getPersistentMeta("quitLocV2"); - if (arr == null) { - return; - } - V2 = true; - removePersistentMeta("quitLocV2"); - } else { - removePersistentMeta("quitLoc"); - } - - if (!getMeta("teleportOnLogin", true)) { - return; - } - ByteBuffer quitWorld = ByteBuffer.wrap(arr); - final int plotX = quitWorld.getShort(); - final int plotZ = quitWorld.getShort(); - PlotId id = PlotId.of(plotX, plotZ); - int x = quitWorld.getInt(); - int y = V2 ? quitWorld.getShort() : (quitWorld.get() & 0xFF); - int z = quitWorld.getInt(); - Plot plot = area.getOwnedPlot(id); - - if (plot == null) { return; } + V2 = true; + removePersistentMeta("quitLocV2"); + } else { + removePersistentMeta("quitLoc"); + } - final Location location = Location.at(plot.getWorldName(), x, y, z); - if (plot.isLoaded()) { - TaskManager.runTask(() -> { - if (getMeta("teleportOnLogin", true)) { - teleport(location, TeleportCause.LOGIN); - sendMessage( - TranslatableCaption.of("teleport.teleported_to_plot")); - } - }); - } else if (!PlotSquared.get().isMainThread(Thread.currentThread())) { + if (!getMeta("teleportOnLogin", true)) { + return; + } + ByteBuffer quitWorld = ByteBuffer.wrap(arr); + final int plotX = quitWorld.getShort(); + final int plotZ = quitWorld.getShort(); + PlotId id = PlotId.of(plotX, plotZ); + int x = quitWorld.getInt(); + int y = V2 ? quitWorld.getShort() : (quitWorld.get() & 0xFF); + int z = quitWorld.getInt(); + Plot plot = area.getOwnedPlot(id); + + if (plot == null) { + return; + } + + final Location location = Location.at(plot.getWorldName(), x, y, z); + if (plot.isLoaded()) { + TaskManager.runTask(() -> { if (getMeta("teleportOnLogin", true)) { - plot.teleportPlayer( - PlotPlayer.this, - result -> TaskManager.runTask(() -> { - if (getMeta("teleportOnLogin", true)) { - if (plot.isLoaded()) { - teleport(location, TeleportCause.LOGIN); - sendMessage(TranslatableCaption - .of("teleport.teleported_to_plot")); - } - } - }) - ); + teleport(location, TeleportCause.LOGIN); + sendMessage( + TranslatableCaption.of("teleport.teleported_to_plot")); } + }); + } else if (!PlotSquared.get().isMainThread(Thread.currentThread())) { + if (getMeta("teleportOnLogin", true)) { + plot.teleportPlayer( + PlotPlayer.this, + result -> TaskManager.runTask(() -> { + if (getMeta("teleportOnLogin", true)) { + if (plot.isLoaded()) { + teleport(location, TeleportCause.LOGIN); + sendMessage(TranslatableCaption + .of("teleport.teleported_to_plot")); + } + } + }) + ); } - } catch (Throwable e) { - LOGGER.error("Error populating persistent meta for player {}", PlotPlayer.this.getName(), e); } + } catch (Throwable e) { + LOGGER.error("Error populating persistent meta for player {}", PlotPlayer.this.getName(), e); } - } - ); + }; + service.getPersistentMeta(getUUID(), resultConsumer); } } @@ -775,7 +774,9 @@ byte[] getPersistentMeta(String key) { Object removePersistentMeta(String key) { final Object old = this.metaMap.remove(key); if (Settings.Enabled_Components.PERSISTENT_META) { - DBFunc.removePersistentMeta(getUUID(), key); + PlayerMetaService service = + PlotSquared.platform().injector().getInstance(PlayerMetaService.class); + service.removePersistentMeta(getUUID(), key); } return old; } @@ -852,7 +853,9 @@ void setPersistentMeta(String key, byte[] value) { boolean delete = hasPersistentMeta(key); this.metaMap.put(key, value); if (Settings.Enabled_Components.PERSISTENT_META) { - DBFunc.addPersistentMeta(getUUID(), key, value, delete); + PlayerMetaService service = + PlotSquared.platform().injector().getInstance(PlayerMetaService.class); + service.addPersistentMeta(getUUID(), key, value, delete); } } From 5822cff13469e0f1a5c2ff5882779a9c17db2683 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 00:05:06 +0200 Subject: [PATCH 118/141] feat: remove deprecated persistent metadata methods from DBFunc --- .../com/plotsquared/core/database/DBFunc.java | 26 ------------------- 1 file changed, 26 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java index 79bf82896c..3fb7dd827b 100644 --- a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java +++ b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java @@ -67,32 +67,6 @@ public class DBFunc { public static final UUID EVERYONE = UUID.fromString("1-1-3-3-7"); public static final UUID SERVER = UUID.fromString("00000000-0000-0000-0000-000000000000"); - public static void addPersistentMeta(UUID uuid, String key, byte[] meta, boolean delete) { - PlayerMetaRepository repo = PlotSquared.platform().injector().getInstance(PlayerMetaRepository.class); - if (delete) { - repo.delete(uuid.toString(), key); - } else { - repo.put(uuid.toString(), key, meta); - } - } - - public static void getPersistentMeta(UUID uuid, RunnableVal> result) { - PlayerMetaRepository repo = PlotSquared.platform().injector().getInstance(PlayerMetaRepository.class); - Map map = new HashMap<>(); - for (PlayerMetaEntity e : repo.findByUuid(uuid.toString())) { - map.put(e.getKey(), e.getPlayerMetaValue()); - } - if (result != null) { - result.run(map); - } - - } - - public static void removePersistentMeta(UUID uuid, String key) { - PlayerMetaRepository repo = PlotSquared.platform().injector().getInstance(PlayerMetaRepository.class); - repo.delete(uuid.toString(), key); - } - public static CompletableFuture swapPlots(Plot plot1, Plot plot2) { if (plot1 == null || plot2 == null) { return CompletableFuture.completedFuture(false); From 5818fe27a85365bd2bbbd9fee2c96737af9d4cd7 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 00:26:47 +0200 Subject: [PATCH 119/141] feat: add PlotService interface for plot management operations --- .../core/services/api/PlotService.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/services/api/PlotService.java diff --git a/Core/src/main/java/com/plotsquared/core/services/api/PlotService.java b/Core/src/main/java/com/plotsquared/core/services/api/PlotService.java new file mode 100644 index 0000000000..2359ca765b --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/api/PlotService.java @@ -0,0 +1,35 @@ +package com.plotsquared.core.services.api; + +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.PlotId; + +import java.util.HashMap; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; + +public interface PlotService { + + CompletableFuture swapPlots(Plot plot1, Plot plot2); + + void movePlot(Plot originalPlot, Plot newPlot); + + void setOwner(Plot plot, UUID uuid); + + void createPlotsAndData(List plots, Runnable whenDone); + + void createPlotSafe( + final Plot plot, final Runnable success, + final Runnable failure + ); + + void createPlotAndSettings(Plot plot, Runnable whenDone); + + void delete(Plot plot); + + @Deprecated(forRemoval = true, since = "8.0.0") + void deleteRatings(Plot plot); + + HashMap> getPlots(); + +} From 08424e2f707c3c113371a48e4768ccc703bacc4e Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 00:26:51 +0200 Subject: [PATCH 120/141] feat: implement PlotDefaultService for plot management operations --- .../services/impl/PlotDefaultService.java | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/services/impl/PlotDefaultService.java diff --git a/Core/src/main/java/com/plotsquared/core/services/impl/PlotDefaultService.java b/Core/src/main/java/com/plotsquared/core/services/impl/PlotDefaultService.java new file mode 100644 index 0000000000..774ea59389 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/impl/PlotDefaultService.java @@ -0,0 +1,77 @@ +package com.plotsquared.core.services.impl; + +import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.persistence.repository.api.PlotRepository; +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.PlotId; +import com.plotsquared.core.services.api.PlotService; +import jakarta.inject.Inject; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; + +public class PlotDefaultService implements PlotService { + + private final PlotRepository repository; + + @Inject + public PlotDefaultService(final PlotRepository repository) { + this.repository = repository; + } + + @Override + public @NotNull CompletableFuture swapPlots(final @NotNull Plot plot1, final @NotNull Plot plot2) { + return CompletableFuture.completedFuture(this.repository.swapPlots(plot1, plot2)); + } + + @Override + public void movePlot(final @NotNull Plot originalPlot, final @NotNull Plot newPlot) { + this.repository.movePlots(originalPlot, newPlot); + } + + @Override + public void setOwner(final @NotNull Plot plot, final @NotNull UUID uuid) { + this.repository.setOwner(plot, uuid); + } + + @Override + public void createPlotsAndData(final @NotNull List plots, final Runnable whenDone) { + this.repository.createPlotsAndData(plots); + whenDone.run(); + } + + @Override + public void createPlotSafe(final @NotNull Plot plot, final @NotNull Runnable success, final Runnable failure) { + boolean created = this.repository.createPlotSafe(plot); + if (created) { + success.run(); + } else { + failure.run(); + } + } + + @Override + public void createPlotAndSettings(final @NotNull Plot plot, final Runnable whenDone) { + this.repository.createPlotAndSettings(plot); + whenDone.run(); + } + + @Override + public void delete(final @NotNull Plot plot) { + this.repository.delete(plot); + } + + @Override + public void deleteRatings(final Plot plot) { + this.repository.deleteRatings(plot); + } + + @Override + public HashMap> getPlots() { + return this.repository.getPlots(); + } + +} From e1f393e4f3aae26cc31a57fb8ef88131e15d4c3e Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 00:26:55 +0200 Subject: [PATCH 121/141] feat: bind PlotService to PlotDefaultService in ServiceModule --- .../com/plotsquared/core/services/config/ServiceModule.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java b/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java index d907a5e5cf..8072847718 100644 --- a/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java +++ b/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java @@ -2,13 +2,16 @@ import com.google.inject.AbstractModule; import com.plotsquared.core.services.api.PlayerMetaService; +import com.plotsquared.core.services.api.PlotService; import com.plotsquared.core.services.impl.PlayerMetaDefaultService; +import com.plotsquared.core.services.impl.PlotDefaultService; public class ServiceModule extends AbstractModule { @Override protected void configure() { bind(PlayerMetaService.class).to(PlayerMetaDefaultService.class); + bind(PlotService.class).to(PlotDefaultService.class); } } From 84b2c4a5e3e45274907bdbe62b1a708e7d7152a3 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 00:27:01 +0200 Subject: [PATCH 122/141] feat: refactor plot ownership and management to use PlotService --- .../java/com/plotsquared/core/plot/Plot.java | 23 ++++++++++++------- .../core/plot/PlotModificationManager.java | 4 +++- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/plot/Plot.java b/Core/src/main/java/com/plotsquared/core/plot/Plot.java index 655dc6d3f5..5fb0b9b120 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/Plot.java +++ b/Core/src/main/java/com/plotsquared/core/plot/Plot.java @@ -53,6 +53,7 @@ import com.plotsquared.core.plot.schematic.Schematic; import com.plotsquared.core.plot.world.SinglePlotArea; import com.plotsquared.core.queue.QueueCoordinator; +import com.plotsquared.core.services.api.PlotService; import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.MathMan; import com.plotsquared.core.util.PlayerManager; @@ -692,17 +693,18 @@ public void setOwner(final @NonNull UUID owner) { this.getPlotModificationManager().create(); return; } + PlotService service = PlotSquared.platform().injector().getInstance(PlotService.class); if (!isMerged()) { if (!owner.equals(this.getOwnerAbs())) { this.setOwnerAbs(owner); - DBFunc.setOwner(this, owner); + service.setOwner(this, owner); } return; } for (final Plot current : getConnectedPlots()) { if (!owner.equals(current.getOwnerAbs())) { current.setOwnerAbs(owner); - DBFunc.setOwner(current, owner); + service.setOwner(current, owner); } } } @@ -1115,17 +1117,18 @@ public boolean setOwner(UUID owner, PlotPlayer initiator) { this.getPlotModificationManager().create(); return true; } + PlotService service = PlotSquared.platform().injector().getInstance(PlotService.class); if (!isMerged()) { if (!owner.equals(this.getOwnerAbs())) { this.setOwnerAbs(owner); - DBFunc.setOwner(this, owner); + service.setOwner(this, owner); } return true; } for (final Plot current : getConnectedPlots()) { if (!owner.equals(current.getOwnerAbs())) { current.setOwnerAbs(owner); - DBFunc.setOwner(current, owner); + service.setOwner(current, owner); } } return true; @@ -1349,7 +1352,7 @@ public boolean unclaim() { } getArea().removePlot(getId()); - DBFunc.delete(current); + PlotSquared.platform().injector().getInstance(PlotService.class).delete(current); current.setOwnerAbs(null); current.settings = null; current.clearCache(); @@ -1718,7 +1721,8 @@ public void clearRatings() { Plot base = this.getBasePlot(false); PlotSettings baseSettings = base.getSettings(); if (baseSettings.getRatings() != null && !baseSettings.getRatings().isEmpty()) { - DBFunc.deleteRatings(base); + PlotService plotService = PlotSquared.platform().injector().getInstance(PlotService.class); + plotService.deleteRatings(base); baseSettings.setRatings(null); } } @@ -1901,7 +1905,9 @@ public CompletableFuture swapData(Plot plot) { this.area.addPlotAbs(this); plot.area.addPlotAbs(plot); // Swap database - return DBFunc.swapPlots(plot, this); + PlotService service = + PlotSquared.platform().injector().getInstance(PlotService.class); + return service.swapPlots(plot, this); } /** @@ -1924,7 +1930,8 @@ public boolean moveData(Plot plot, Runnable whenDone) { this.id = plot.getId(); this.area.addPlotAbs(this); clearCache(); - DBFunc.movePlot(this, plot); + PlotService service = PlotSquared.platform().injector().getInstance(PlotService.class); + service.movePlot(this, plot); TaskManager.runTaskLater(whenDone, TaskTime.ticks(1L)); return true; } diff --git a/Core/src/main/java/com/plotsquared/core/plot/PlotModificationManager.java b/Core/src/main/java/com/plotsquared/core/plot/PlotModificationManager.java index cc2f1f0709..49802c7f1a 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/PlotModificationManager.java +++ b/Core/src/main/java/com/plotsquared/core/plot/PlotModificationManager.java @@ -38,6 +38,7 @@ import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.flag.PlotFlag; import com.plotsquared.core.queue.QueueCoordinator; +import com.plotsquared.core.services.api.PlotService; import com.plotsquared.core.util.task.TaskManager; import com.plotsquared.core.util.task.TaskTime; import com.sk89q.worldedit.function.pattern.Pattern; @@ -516,7 +517,8 @@ public boolean create(final @NonNull UUID uuid, final boolean notify) { this.plot.getDenied().clear(); this.plot.settings = new PlotSettings(); if (this.plot.getArea().addPlot(this.plot)) { - DBFunc.createPlotAndSettings(this.plot, () -> { + final PlotService service = PlotSquared.platform().injector().getInstance(PlotService.class); + service.createPlotAndSettings(this.plot, () -> { PlotArea plotworld = plot.getArea(); if (notify && plotworld.isAutoMerge()) { final PlotPlayer player = PlotSquared.platform().playerManager().getPlayerIfExists(uuid); From f8f9d5f91b3429fe72642f32f1a3d8a992821ee4 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 00:27:06 +0200 Subject: [PATCH 123/141] feat: refactor plot creation and retrieval to use PlotService --- Core/src/main/java/com/plotsquared/core/command/Auto.java | 4 +++- Core/src/main/java/com/plotsquared/core/command/Claim.java | 5 ++++- .../java/com/plotsquared/core/command/DebugLoadTest.java | 5 +++-- .../java/com/plotsquared/core/command/DebugSaveTest.java | 5 ++++- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/command/Auto.java b/Core/src/main/java/com/plotsquared/core/command/Auto.java index 0ca8650d42..10bb90ddf1 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Auto.java +++ b/Core/src/main/java/com/plotsquared/core/command/Auto.java @@ -35,6 +35,7 @@ import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.world.PlotAreaManager; +import com.plotsquared.core.services.api.PlotService; import com.plotsquared.core.services.plots.AutoQuery; import com.plotsquared.core.services.plots.AutoService; import com.plotsquared.core.util.EconHandler; @@ -176,7 +177,8 @@ public void run(final Plot plot) { } }; - DBFunc.createPlotSafe(plot, successRunner, () -> {}); + PlotService service = PlotSquared.platform().injector().getInstance(PlotService.class); + service.createPlotSafe(plot, successRunner, () -> {}); } diff --git a/Core/src/main/java/com/plotsquared/core/command/Claim.java b/Core/src/main/java/com/plotsquared/core/command/Claim.java index 422347449a..779ac5f02f 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Claim.java +++ b/Core/src/main/java/com/plotsquared/core/command/Claim.java @@ -19,6 +19,7 @@ package com.plotsquared.core.command; import com.google.inject.Inject; +import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.caption.TranslatableCaption; import com.plotsquared.core.database.DBFunc; @@ -32,6 +33,7 @@ import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; +import com.plotsquared.core.services.api.PlotService; import com.plotsquared.core.util.EconHandler; import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.PlotExpression; @@ -199,7 +201,8 @@ public boolean onCommand(final PlotPlayer player, String[] args) { } plot.setOwnerAbs(player.getUUID()); final String finalSchematic = schematic; - DBFunc.createPlotSafe(plot, () -> { + PlotService service = PlotSquared.platform().injector().getInstance(PlotService.class); + service.createPlotSafe(plot, () -> { try { TaskManager.getPlatformImplementation().sync(() -> { if (!plot.claim(player, true, finalSchematic, false, false)) { diff --git a/Core/src/main/java/com/plotsquared/core/command/DebugLoadTest.java b/Core/src/main/java/com/plotsquared/core/command/DebugLoadTest.java index 8416a00b55..3362058977 100644 --- a/Core/src/main/java/com/plotsquared/core/command/DebugLoadTest.java +++ b/Core/src/main/java/com/plotsquared/core/command/DebugLoadTest.java @@ -19,8 +19,8 @@ package com.plotsquared.core.command; import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.player.PlotPlayer; +import com.plotsquared.core.services.api.PlotService; @CommandDeclaration(command = "debugloadtest", permission = "plots.debugloadtest", @@ -31,7 +31,8 @@ public class DebugLoadTest extends SubCommand { @Override public boolean onCommand(PlotPlayer player, String[] args) { - PlotSquared.get().plots_tmp = DBFunc.getPlots(); + PlotService plotService = PlotSquared.platform().injector().getInstance(PlotService.class); + PlotSquared.get().plots_tmp = plotService.getPlots(); return true; } diff --git a/Core/src/main/java/com/plotsquared/core/command/DebugSaveTest.java b/Core/src/main/java/com/plotsquared/core/command/DebugSaveTest.java index 2e259b8f85..cad1e3f25e 100644 --- a/Core/src/main/java/com/plotsquared/core/command/DebugSaveTest.java +++ b/Core/src/main/java/com/plotsquared/core/command/DebugSaveTest.java @@ -18,10 +18,12 @@ */ package com.plotsquared.core.command; +import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.caption.TranslatableCaption; import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.services.api.PlotService; import com.plotsquared.core.util.query.PlotQuery; import java.util.List; @@ -37,7 +39,8 @@ public class DebugSaveTest extends SubCommand { public boolean onCommand(final PlotPlayer player, String[] args) { final List plots = PlotQuery.newQuery().allPlots().asList(); player.sendMessage(TranslatableCaption.of("debugsavetest.starting")); - DBFunc.createPlotsAndData( + PlotService service = PlotSquared.platform().injector().getInstance(PlotService.class); + service.createPlotsAndData( plots, () -> player.sendMessage(TranslatableCaption.of("debugsavetest.done")) ); From 4a505918bd69113a2e83e2d281f1e0c9d22b7ea9 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 00:27:12 +0200 Subject: [PATCH 124/141] feat: remove deprecated plot management methods from DBFunc --- .../com/plotsquared/core/database/DBFunc.java | 180 ------------------ 1 file changed, 180 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java index 3fb7dd827b..54013a1b3e 100644 --- a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java +++ b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java @@ -67,167 +67,6 @@ public class DBFunc { public static final UUID EVERYONE = UUID.fromString("1-1-3-3-7"); public static final UUID SERVER = UUID.fromString("00000000-0000-0000-0000-000000000000"); - public static CompletableFuture swapPlots(Plot plot1, Plot plot2) { - if (plot1 == null || plot2 == null) { - return CompletableFuture.completedFuture(false); - } - PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - return CompletableFuture.completedFuture(repo.swapPlots(plot1, plot2)); - } - - public static void movePlot(Plot originalPlot, Plot newPlot) { - if (originalPlot == null || newPlot == null) { - return; - } - PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - repo.movePlots(originalPlot, newPlot); - } - - /** - * Set the owner of a plot - * - * @param plot Plot Object - * @param uuid New Owner - */ - public static void setOwner(Plot plot, UUID uuid) { - PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - repo.setOwner(plot, uuid); - } - - /** - * Create all settings + (trusted, denied, members) - * - * @param plots List containing all plot objects - */ - public static void createPlotsAndData(List plots, Runnable whenDone) { - PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - repo.createPlotsAndData(plots); - if (whenDone != null) whenDone.run(); - } - - public static void createPlotSafe( - final Plot plot, final Runnable success, - final Runnable failure - ) { - PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - boolean created = repo.createPlotSafe(plot); - if (created) { - if (success != null) success.run(); - } else { - if (failure != null) failure.run(); - } - } - - /** - * Create a plot. - * - * @param plot Plot to create - */ - public static void createPlotAndSettings(Plot plot, Runnable whenDone) { - PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - repo.createPlotAndSettings(plot); - if (whenDone != null) whenDone.run(); - } - - /** - * Delete a plot. - * - * @param plot Plot to delete - */ - public static void delete(Plot plot) { - PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - repo.delete(plot); - } - - /** - * Delete the ratings for a plot. - * - * @param plot - */ - public static void deleteRatings(Plot plot) { - PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - repo.deleteRatings(plot); - } - - /** - * Delete the trusted list for a plot. - * - * @param plot - */ - public static void deleteTrusted(Plot plot) { - try { - PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - String world = plot.getWorldName(); - var peOpt = repo.findByWorldAndId(world, plot.getId().getX(), plot.getId().getY()); - peOpt.ifPresent(pe -> { - PlotMembershipRepository mRepo = PlotSquared.platform().injector().getInstance(PlotMembershipRepository.class); - mRepo.deleteByPlotId(pe.getId()); - }); - } catch (Throwable ignored) { - } - } - - /** - * Delete the members list for a plot. - * - * @param plot - */ - public static void deleteMembers(Plot plot) { - PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - String world = plot.getWorldName(); - var peOpt = repo.findByWorldAndId(world, plot.getId().getX(), plot.getId().getY()); - peOpt.ifPresent(pe -> { - PlotTrustedRepository tRepo = PlotSquared.platform().injector().getInstance(PlotTrustedRepository.class); - tRepo.deleteByPlotId(pe.getId()); - }); - } - - /** - * Delete the denied list for a plot. - * - * @param plot - */ - public static void deleteDenied(Plot plot) { - PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - String world = plot.getWorldName(); - var peOpt = repo.findByWorldAndId(world, plot.getId().getX(), plot.getId().getY()); - peOpt.ifPresent(pe -> { - PlotDeniedRepository dRepo = PlotSquared.platform().injector().getInstance(PlotDeniedRepository.class); - dRepo.deleteByPlotId(pe.getId()); - }); - } - - /** - * Delete the comments in a plot. - * - * @param plot - */ - public static void deleteComments(Plot plot) { - PlotCommentRepository repo = PlotSquared.platform().injector().getInstance(PlotCommentRepository.class); - String world = plot.getWorldName(); - int hash = plot.getId().hashCode(); - repo.deleteByWorldAndHash(world, hash); - } - - /** - * Deleting settings will - * 1) Delete any settings (flags and such) associated with the plot - * 2) Prevent any local changes to the plot from saving properly to the db - *

- * This shouldn't ever be needed - * - * @param plot - */ - public static void deleteSettings(Plot plot) { - PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - String world = plot.getWorldName(); - var peOpt = repo.findByWorldAndId(world, plot.getId().getX(), plot.getId().getY()); - peOpt.ifPresent(pe -> { - PlotSettingsRepository sRepo = PlotSquared.platform().injector().getInstance(PlotSettingsRepository.class); - sRepo.deleteByPlotId(pe.getId()); - }); - } - public static void delete(PlotCluster toDelete) { if (toDelete == null) { return; @@ -242,25 +81,6 @@ public static void delete(PlotCluster toDelete) { ce.ifPresent(entity -> clusterRepo.deleteById(entity.getId())); } - /** - * Create plot settings. - * - * @param id Plot ID - * @param plot Plot Object - */ - public static void createPlotSettings(int id, Plot plot) { - PlotSettingsRepository repo = PlotSquared.platform().injector().getInstance(PlotSettingsRepository.class); - repo.createDefaultIfAbsent(id, "DEFAULT"); - } - - /** - * @return Plots - */ - public static HashMap> getPlots() { - PlotRepository repo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - return repo.getPlots(); - } - public static void setMerged(Plot plot, boolean[] merged) { if (plot == null || merged == null) { return; From 0e73fd7bd975528bef609235f7ae34fbec9de231 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 00:28:30 +0200 Subject: [PATCH 125/141] feat: remove unused DBFunc imports across multiple files --- .../com/plotsquared/core/command/Auto.java | 1 - .../com/plotsquared/core/command/Claim.java | 1 - .../core/command/DebugSaveTest.java | 1 - .../com/plotsquared/core/command/Grant.java | 3 --- .../com/plotsquared/core/database/DBFunc.java | 3 --- .../core/services/api/PlayerMetaService.java | 18 ++++++++++++++++++ .../core/services/api/PlotService.java | 18 ++++++++++++++++++ .../core/services/config/ServiceModule.java | 18 ++++++++++++++++++ .../impl/PlayerMetaDefaultService.java | 19 ++++++++++++++++++- .../services/impl/PlotDefaultService.java | 19 ++++++++++++++++++- 10 files changed, 90 insertions(+), 11 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/command/Auto.java b/Core/src/main/java/com/plotsquared/core/command/Auto.java index 10bb90ddf1..8b05b131ef 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Auto.java +++ b/Core/src/main/java/com/plotsquared/core/command/Auto.java @@ -23,7 +23,6 @@ import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.events.PlayerAutoPlotEvent; import com.plotsquared.core.events.PlotAutoMergeEvent; import com.plotsquared.core.events.Result; diff --git a/Core/src/main/java/com/plotsquared/core/command/Claim.java b/Core/src/main/java/com/plotsquared/core/command/Claim.java index 779ac5f02f..640f6c28bb 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Claim.java +++ b/Core/src/main/java/com/plotsquared/core/command/Claim.java @@ -22,7 +22,6 @@ import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.events.PlayerClaimPlotEvent; import com.plotsquared.core.events.PlotMergeEvent; import com.plotsquared.core.events.Result; diff --git a/Core/src/main/java/com/plotsquared/core/command/DebugSaveTest.java b/Core/src/main/java/com/plotsquared/core/command/DebugSaveTest.java index cad1e3f25e..d5273dba36 100644 --- a/Core/src/main/java/com/plotsquared/core/command/DebugSaveTest.java +++ b/Core/src/main/java/com/plotsquared/core/command/DebugSaveTest.java @@ -20,7 +20,6 @@ import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.services.api.PlotService; diff --git a/Core/src/main/java/com/plotsquared/core/command/Grant.java b/Core/src/main/java/com/plotsquared/core/command/Grant.java index 0531733bd6..4b94ddf73d 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Grant.java +++ b/Core/src/main/java/com/plotsquared/core/command/Grant.java @@ -21,16 +21,13 @@ import com.google.common.primitives.Ints; import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.permissions.Permission; -import com.plotsquared.core.persistence.repository.api.PlayerMetaRepository; import com.plotsquared.core.player.MetaDataAccess; import com.plotsquared.core.player.PlayerMetaDataKeys; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.services.api.PlayerMetaService; import com.plotsquared.core.util.PlayerManager; import com.plotsquared.core.util.TabCompletions; -import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.RunnableVal2; import com.plotsquared.core.util.task.RunnableVal3; import net.kyori.adventure.text.Component; diff --git a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java index 54013a1b3e..14203bbb77 100644 --- a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java +++ b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java @@ -20,7 +20,6 @@ import com.plotsquared.core.PlotSquared; import com.plotsquared.core.persistence.entity.ClusterEntity; -import com.plotsquared.core.persistence.entity.PlayerMetaEntity; import com.plotsquared.core.persistence.entity.PlotCommentEntity; import com.plotsquared.core.persistence.entity.PlotEntity; import com.plotsquared.core.persistence.entity.PlotFlagEntity; @@ -28,7 +27,6 @@ import com.plotsquared.core.persistence.repository.api.ClusterInvitedRepository; import com.plotsquared.core.persistence.repository.api.ClusterRepository; import com.plotsquared.core.persistence.repository.api.ClusterSettingsRepository; -import com.plotsquared.core.persistence.repository.api.PlayerMetaRepository; import com.plotsquared.core.persistence.repository.api.PlotCommentRepository; import com.plotsquared.core.persistence.repository.api.PlotDeniedRepository; import com.plotsquared.core.persistence.repository.api.PlotFlagRepository; @@ -52,7 +50,6 @@ import java.util.Optional; import java.util.Set; import java.util.UUID; -import java.util.concurrent.CompletableFuture; /** * Database Functions diff --git a/Core/src/main/java/com/plotsquared/core/services/api/PlayerMetaService.java b/Core/src/main/java/com/plotsquared/core/services/api/PlayerMetaService.java index ff8fc0329d..69fd86a0c1 100644 --- a/Core/src/main/java/com/plotsquared/core/services/api/PlayerMetaService.java +++ b/Core/src/main/java/com/plotsquared/core/services/api/PlayerMetaService.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.services.api; import java.util.Map; diff --git a/Core/src/main/java/com/plotsquared/core/services/api/PlotService.java b/Core/src/main/java/com/plotsquared/core/services/api/PlotService.java index 2359ca765b..94ea50260a 100644 --- a/Core/src/main/java/com/plotsquared/core/services/api/PlotService.java +++ b/Core/src/main/java/com/plotsquared/core/services/api/PlotService.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.services.api; import com.plotsquared.core.plot.Plot; diff --git a/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java b/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java index 8072847718..953e3257cb 100644 --- a/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java +++ b/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.services.config; import com.google.inject.AbstractModule; diff --git a/Core/src/main/java/com/plotsquared/core/services/impl/PlayerMetaDefaultService.java b/Core/src/main/java/com/plotsquared/core/services/impl/PlayerMetaDefaultService.java index 23346c3fd2..b77cdf29b3 100644 --- a/Core/src/main/java/com/plotsquared/core/services/impl/PlayerMetaDefaultService.java +++ b/Core/src/main/java/com/plotsquared/core/services/impl/PlayerMetaDefaultService.java @@ -1,6 +1,23 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.services.impl; -import com.plotsquared.core.PlotSquared; import com.plotsquared.core.persistence.entity.PlayerMetaEntity; import com.plotsquared.core.persistence.repository.api.PlayerMetaRepository; import com.plotsquared.core.services.api.PlayerMetaService; diff --git a/Core/src/main/java/com/plotsquared/core/services/impl/PlotDefaultService.java b/Core/src/main/java/com/plotsquared/core/services/impl/PlotDefaultService.java index 774ea59389..71287ffdc1 100644 --- a/Core/src/main/java/com/plotsquared/core/services/impl/PlotDefaultService.java +++ b/Core/src/main/java/com/plotsquared/core/services/impl/PlotDefaultService.java @@ -1,6 +1,23 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.services.impl; -import com.plotsquared.core.PlotSquared; import com.plotsquared.core.persistence.repository.api.PlotRepository; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotId; From aedce452b08bed4e39307bf36b7707c09bcfe056 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 00:56:19 +0200 Subject: [PATCH 126/141] feat: add ClusterService interface for plot cluster management --- .../core/services/api/ClusterService.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/services/api/ClusterService.java diff --git a/Core/src/main/java/com/plotsquared/core/services/api/ClusterService.java b/Core/src/main/java/com/plotsquared/core/services/api/ClusterService.java new file mode 100644 index 0000000000..fe017f7407 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/api/ClusterService.java @@ -0,0 +1,32 @@ +package com.plotsquared.core.services.api; + +import com.plotsquared.core.plot.PlotCluster; +import com.plotsquared.core.plot.PlotId; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Set; +import java.util.UUID; + +public interface ClusterService { + + void createCluster(PlotCluster cluster); + + void resizeCluster(PlotCluster cluster, PlotId min, PlotId max); + + void removeHelper(PlotCluster cluster, UUID uuid); + + void delete(PlotCluster cluster); + + HashMap> getClusters(); + + void setPosition(PlotCluster cluster, String position); + + void setInvited(PlotCluster cluster, UUID uuid); + + void removeInvited(PlotCluster cluster, UUID uuid); + + void setHelper(PlotCluster cluster, UUID uuid); + + void replaceWorld(String oldWorld, String newWorld, @Nullable PlotId min, PlotId max); +} From 3463913af4a0f7b059e882890e4bc6253514fef3 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 00:56:25 +0200 Subject: [PATCH 127/141] feat: implement ClusterDefaultService for cluster management functionality --- .../services/impl/ClusterDefaultService.java | 194 ++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/services/impl/ClusterDefaultService.java diff --git a/Core/src/main/java/com/plotsquared/core/services/impl/ClusterDefaultService.java b/Core/src/main/java/com/plotsquared/core/services/impl/ClusterDefaultService.java new file mode 100644 index 0000000000..8dacff568c --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/impl/ClusterDefaultService.java @@ -0,0 +1,194 @@ +package com.plotsquared.core.services.impl; + +import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.persistence.entity.ClusterEntity; +import com.plotsquared.core.persistence.repository.api.ClusterHelperRepository; +import com.plotsquared.core.persistence.repository.api.ClusterInvitedRepository; +import com.plotsquared.core.persistence.repository.api.ClusterRepository; +import com.plotsquared.core.persistence.repository.api.ClusterSettingsRepository; +import com.plotsquared.core.persistence.repository.api.PlotRepository; +import com.plotsquared.core.plot.PlotCluster; +import com.plotsquared.core.plot.PlotId; +import com.plotsquared.core.services.api.ClusterService; +import jakarta.inject.Inject; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; + +public class ClusterDefaultService implements ClusterService { + + private final ClusterRepository repository; + private final ClusterHelperRepository helperRepository; + private final ClusterInvitedRepository invitedRepo; + private final ClusterSettingsRepository settingsRepo; + private final PlotRepository plotRepository; + + @Inject + public ClusterDefaultService(final ClusterRepository repository, final ClusterHelperRepository helperRepository, + final ClusterInvitedRepository repo, final ClusterSettingsRepository settingsRepo, + final PlotRepository plotRepository + ) { + this.repository = repository; + this.helperRepository = helperRepository; + this.invitedRepo = repo; + this.settingsRepo = settingsRepo; + this.plotRepository = plotRepository; + } + + @Override + public void createCluster(final PlotCluster cluster) { + ClusterEntity e = new ClusterEntity(); + e.setWorld(cluster.area != null ? cluster.area.toString() : null); + e.setOwner(cluster.owner != null ? cluster.owner.toString() : null); + if (cluster.getP1() != null) { + e.setPos1X(cluster.getP1().getX()); + e.setPos1Z(cluster.getP1().getY()); + } + if (cluster.getP2() != null) { + e.setPos2X(cluster.getP2().getX()); + e.setPos2Z(cluster.getP2().getY()); + } + this.repository.save(e); + } + + @Override + public void resizeCluster(final PlotCluster cluster, final PlotId min, final PlotId max) { + String world = cluster.area != null ? cluster.area.toString() : null; + PlotId center = cluster.getCenterPlotId(); + if (world != null) { + Optional ent = this.repository.findByWorldAndBounds(world, center.getX(), center.getY()); + if (ent.isPresent()) { + ClusterEntity e = ent.get(); + e.setPos1X(min.getX()); + e.setPos1Z(min.getY()); + e.setPos2X(max.getX()); + e.setPos2Z(max.getY()); + this.repository.save(e); + } + } + } + + @Override + public void removeHelper(final PlotCluster cluster, final @NotNull UUID uuid) { + String world = cluster.area != null ? cluster.area.toString() : null; + PlotId center = cluster.getCenterPlotId(); + if (world != null) { + Optional ent = this.repository.findByWorldAndBounds(world, center.getX(), center.getY()); + if (ent.isPresent() && ent.get().getId() != null) { + this.helperRepository.remove(ent.get().getId(), uuid.toString()); + } + } + } + + @Override + public void delete(final PlotCluster cluster) { + String world = cluster.area != null ? cluster.area.getWorldName() : null; + if (world == null) { + return; + } + PlotId center = cluster.getCenterPlotId(); + Optional ce = this.repository.findByWorldAndBounds(world, center.getX(), center.getY()); + ce.ifPresent(entity -> this.repository.deleteById(entity.getId())); + } + + @Override + public HashMap> getClusters() { + HashMap> result = new HashMap<>(); + List clusters = this.repository.findAll(); + Map built = new HashMap<>(); + for (ClusterEntity ce : clusters) { + UUID owner = Optional.ofNullable(ce.getOwner()).map(UUID::fromString).orElse(null); + PlotCluster cluster = new PlotCluster(null, PlotId.of(ce.getPos1X(), ce.getPos1Z()), PlotId.of(ce.getPos2X(), ce.getPos2Z()), owner); + built.put(ce.getId(), cluster); + result.computeIfAbsent(ce.getWorld(), k -> new HashSet<>()).add(cluster); + } + // Populate helpers and invited + for (Map.Entry e : built.entrySet()) { + long id = e.getKey(); + PlotCluster cluster = e.getValue(); + for (String u : this.helperRepository.findUsers(id)) { + cluster.helpers.add(UUID.fromString(u)); + } + for (String u : this.invitedRepo.findUsers(id)) { + cluster.invited.add(UUID.fromString(u)); + } + // Apply settings (alias, merged). Avoid setting temp variable. + this.settingsRepo.findById(id).ifPresent(se -> { + if (se.getAlias() != null) { + cluster.settings.setAlias(se.getAlias()); + } + Integer m = se.getMerged(); + if (m != null) { + boolean[] merged = new boolean[4]; + for (int i = 0; i < 4; i++) { + merged[3 - i] = (m & 1 << i) != 0; + } + cluster.settings.setMerged(merged); + } + }); + } + return result; + } + + @Override + public void setPosition(final PlotCluster cluster, final String position) { + String world = cluster.area != null ? cluster.area.getWorldName() : null; + if (world == null) { + return; + } + PlotId center = cluster.getCenterPlotId(); + Optional ce = this.repository.findByWorldAndBounds(world, center.getX(), center.getY()); + ce.ifPresent(entity -> this.settingsRepo.updatePosition(entity.getId(), position)); + } + + @Override + public void setInvited(final PlotCluster cluster, final UUID uuid) { + String world = cluster.area != null ? cluster.area.getWorldName() : null; + if (world == null) { + return; + } + PlotId center = cluster.getCenterPlotId(); + Optional ce = this.repository.findByWorldAndBounds(world, center.getX(), center.getY()); + ce.ifPresent(entity -> this.invitedRepo.add(entity.getId(), uuid.toString())); + } + + @Override + public void removeInvited(final PlotCluster cluster, final UUID uuid) { + String world = cluster.area != null ? cluster.area.getWorldName() : null; + if (world == null) { + return; + } + PlotId center = cluster.getCenterPlotId(); + Optional ce = this.repository.findByWorldAndBounds(world, center.getX(), center.getY()); + ce.ifPresent(entity -> this.invitedRepo.remove(entity.getId(), uuid.toString())); + } + + @Override + public void setHelper(final PlotCluster cluster, final UUID uuid) { + String world = cluster.area != null ? cluster.area.getWorldName() : null; + if (world == null) { + return; + } + PlotId center = cluster.getCenterPlotId(); + Optional ce = this.repository.findByWorldAndBounds(world, center.getX(), center.getY()); + ce.ifPresent(entity -> this.helperRepository.add(entity.getId(), uuid.toString())); + } + + @Override + public void replaceWorld(final @NotNull String oldWorld, final @NotNull String newWorld, final PlotId min, final PlotId max) { + if (min == null) { + this.plotRepository.replaceWorld(oldWorld, newWorld); + this.repository.replaceWorld(oldWorld, newWorld); + } else { + this.plotRepository.replaceWorldInBounds(oldWorld, newWorld, min, max); + this.repository.replaceWorldInBounds(oldWorld, newWorld, min, max); + } + } + +} From c8986494e571a949c6ef73e90d99f98faf087234 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 00:56:29 +0200 Subject: [PATCH 128/141] feat: refactor cluster management to use ClusterService for database operations --- .../com/plotsquared/core/command/Cluster.java | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/command/Cluster.java b/Core/src/main/java/com/plotsquared/core/command/Cluster.java index f52a56616b..3a01a148c4 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Cluster.java +++ b/Core/src/main/java/com/plotsquared/core/command/Cluster.java @@ -32,6 +32,7 @@ import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotCluster; import com.plotsquared.core.plot.PlotId; +import com.plotsquared.core.services.api.ClusterService; import com.plotsquared.core.util.ComponentHelper; import com.plotsquared.core.util.TabCompletions; import com.plotsquared.core.util.query.PlotQuery; @@ -252,13 +253,13 @@ public boolean onCommand(PlotPlayer player, String[] args) { // create cluster cluster.settings.setAlias(name); area.addCluster(cluster); - DBFunc.createCluster(cluster); + PlotSquared.platform().injector().getInstance(ClusterService.class).createCluster(cluster); // Add any existing plots to the current cluster for (Plot plot : plots) { if (plot.hasOwner()) { if (!cluster.isAdded(plot.getOwner())) { cluster.invited.add(plot.getOwner()); - DBFunc.setInvited(cluster, plot.getOwner()); + PlotSquared.platform().injector().getInstance(ClusterService.class).setInvited(cluster, plot.getOwner()); } } } @@ -320,7 +321,7 @@ public boolean onCommand(PlotPlayer player, String[] args) { return false; } } - DBFunc.delete(cluster); + PlotSquared.platform().injector().getInstance(ClusterService.class).delete(cluster); player.sendMessage(TranslatableCaption.of("cluster.cluster_deleted"), TagResolver.resolver( "cluster", Tag.inserting(Component.text(cluster.toString())) @@ -444,7 +445,7 @@ public boolean onCommand(PlotPlayer player, String[] args) { return false; } // resize cluster - DBFunc.resizeCluster(cluster, pos1, pos2); + PlotSquared.platform().injector().getInstance(ClusterService.class).resizeCluster(cluster, pos1, pos2); player.sendMessage(TranslatableCaption.of("cluster.cluster_resized")); return true; } @@ -502,7 +503,7 @@ public boolean onCommand(PlotPlayer player, String[] args) { if (!cluster.isAdded(uuid)) { // add the user if not added cluster.invited.add(uuid); - DBFunc.setInvited(cluster, uuid); + PlotSquared.platform().injector().getInstance(ClusterService.class).setInvited(cluster, uuid); final PlotPlayer otherPlayer = PlotSquared.platform().playerManager().getPlayerIfExists(uuid); if (otherPlayer != null) { @@ -577,10 +578,10 @@ public boolean onCommand(PlotPlayer player, String[] args) { } else { if (cluster.helpers.contains(uuid)) { cluster.helpers.remove(uuid); - DBFunc.removeHelper(cluster, uuid); + PlotSquared.platform().injector().getInstance(ClusterService.class).removeHelper(cluster, uuid); } cluster.invited.remove(uuid); - DBFunc.removeInvited(cluster, uuid); + PlotSquared.platform().injector().getInstance(ClusterService.class).removeInvited(cluster, uuid); final PlotPlayer player2 = PlotSquared.platform().playerManager().getPlayerIfExists(uuid); @@ -647,10 +648,10 @@ public boolean onCommand(PlotPlayer player, String[] args) { } if (cluster.helpers.contains(uuid)) { cluster.helpers.remove(uuid); - DBFunc.removeHelper(cluster, uuid); + PlotSquared.platform().injector().getInstance(ClusterService.class).removeHelper(cluster, uuid); } cluster.invited.remove(uuid); - DBFunc.removeInvited(cluster, uuid); + PlotSquared.platform().injector().getInstance(ClusterService.class).removeInvited(cluster, uuid); player.sendMessage( TranslatableCaption.of("cluster.cluster_removed"), TagResolver.resolver("cluster", Tag.inserting(Component.text(cluster.getName()))) @@ -701,11 +702,11 @@ public boolean onCommand(PlotPlayer player, String[] args) { } else { if (args[1].equalsIgnoreCase("add")) { cluster.helpers.add(uuid); - DBFunc.setHelper(cluster, uuid); + PlotSquared.platform().injector().getInstance(ClusterService.class).setHelper(cluster, uuid); player.sendMessage(TranslatableCaption.of("cluster.cluster_added_helper")); } else if (args[1].equalsIgnoreCase("remove")) { cluster.helpers.remove(uuid); - DBFunc.removeHelper(cluster, uuid); + PlotSquared.platform().injector().getInstance(ClusterService.class).removeHelper(cluster, uuid); player.sendMessage(TranslatableCaption.of("cluster.cluster_removed_helper")); } else { player.sendMessage( @@ -872,7 +873,7 @@ public boolean onCommand(PlotPlayer player, String[] args) { Location relative = player.getLocation().subtract(base.getX(), 0, base.getZ()); BlockLoc blockloc = new BlockLoc(relative.getX(), relative.getY(), relative.getZ()); cluster.settings.setPosition(blockloc); - DBFunc.setPosition( + PlotSquared.platform().injector().getInstance(ClusterService.class).setPosition( cluster, relative.getX() + "," + relative.getY() + "," + relative.getZ() ); From c3eced0578fb823104e25fb15862433976f5f47a Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 00:56:38 +0200 Subject: [PATCH 129/141] feat: integrate ClusterService for world replacement in PlotSquared --- Core/src/main/java/com/plotsquared/core/PlotSquared.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Core/src/main/java/com/plotsquared/core/PlotSquared.java b/Core/src/main/java/com/plotsquared/core/PlotSquared.java index 18152549b9..1b825ef538 100644 --- a/Core/src/main/java/com/plotsquared/core/PlotSquared.java +++ b/Core/src/main/java/com/plotsquared/core/PlotSquared.java @@ -51,6 +51,7 @@ import com.plotsquared.core.plot.expiration.ExpiryTask; import com.plotsquared.core.plot.flag.GlobalFlagContainer; import com.plotsquared.core.plot.world.PlotAreaManager; +import com.plotsquared.core.services.api.ClusterService; import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.FileUtils; import com.plotsquared.core.util.LegacyConverter; @@ -876,7 +877,8 @@ public void loadWorld( String name = cluster.getName(); // Cluster name String fullId = name + "-" + pos1 + "-" + pos2; worldSection.createSection("areas." + fullId); - DBFunc.replaceWorld(world, world + ";" + name, pos1, pos2); // NPE + PlotSquared.platform().injector().getInstance(ClusterService.class).replaceWorld(world, world + ";" + name, pos1, pos2); + // NPE LOGGER.info("- {}-{}-{}", name, pos1, pos2); GeneratorWrapper areaGen = this.platform.getGenerator(world, gen_string); if (areaGen == null) { From 37ba723f66ce4de7f56355fc9d47ad76cc6d90f0 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 00:57:07 +0200 Subject: [PATCH 130/141] feat: bind ClusterService to ClusterDefaultService in ServiceModule --- .../com/plotsquared/core/services/config/ServiceModule.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java b/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java index 953e3257cb..0855f13120 100644 --- a/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java +++ b/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java @@ -19,8 +19,10 @@ package com.plotsquared.core.services.config; import com.google.inject.AbstractModule; +import com.plotsquared.core.services.api.ClusterService; import com.plotsquared.core.services.api.PlayerMetaService; import com.plotsquared.core.services.api.PlotService; +import com.plotsquared.core.services.impl.ClusterDefaultService; import com.plotsquared.core.services.impl.PlayerMetaDefaultService; import com.plotsquared.core.services.impl.PlotDefaultService; @@ -30,6 +32,7 @@ public class ServiceModule extends AbstractModule { protected void configure() { bind(PlayerMetaService.class).to(PlayerMetaDefaultService.class); bind(PlotService.class).to(PlotDefaultService.class); + bind(ClusterService.class).to(ClusterDefaultService.class); } } From de4a63b5b46870262aa60fee094be04162e63137 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 00:57:11 +0200 Subject: [PATCH 131/141] feat: remove unused Cluster-related methods from DBFunc --- .../com/plotsquared/core/database/DBFunc.java | 197 ------------------ 1 file changed, 197 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java index 14203bbb77..747098f737 100644 --- a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java +++ b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java @@ -19,14 +19,9 @@ package com.plotsquared.core.database; import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.persistence.entity.ClusterEntity; import com.plotsquared.core.persistence.entity.PlotCommentEntity; import com.plotsquared.core.persistence.entity.PlotEntity; import com.plotsquared.core.persistence.entity.PlotFlagEntity; -import com.plotsquared.core.persistence.repository.api.ClusterHelperRepository; -import com.plotsquared.core.persistence.repository.api.ClusterInvitedRepository; -import com.plotsquared.core.persistence.repository.api.ClusterRepository; -import com.plotsquared.core.persistence.repository.api.ClusterSettingsRepository; import com.plotsquared.core.persistence.repository.api.PlotCommentRepository; import com.plotsquared.core.persistence.repository.api.PlotDeniedRepository; import com.plotsquared.core.persistence.repository.api.PlotFlagRepository; @@ -37,7 +32,6 @@ import com.plotsquared.core.persistence.repository.api.PlotTrustedRepository; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; -import com.plotsquared.core.plot.PlotCluster; import com.plotsquared.core.plot.PlotId; import com.plotsquared.core.plot.comment.PlotComment; import com.plotsquared.core.plot.flag.PlotFlag; @@ -46,7 +40,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.UUID; @@ -64,20 +57,6 @@ public class DBFunc { public static final UUID EVERYONE = UUID.fromString("1-1-3-3-7"); public static final UUID SERVER = UUID.fromString("00000000-0000-0000-0000-000000000000"); - public static void delete(PlotCluster toDelete) { - if (toDelete == null) { - return; - } - ClusterRepository clusterRepo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); - String world = toDelete.area != null ? toDelete.area.getWorldName() : null; - if (world == null) { - return; - } - PlotId center = toDelete.getCenterPlotId(); - Optional ce = clusterRepo.findByWorldAndBounds(world, center.getX(), center.getY()); - ce.ifPresent(entity -> clusterRepo.deleteById(entity.getId())); - } - public static void setMerged(Plot plot, boolean[] merged) { if (plot == null || merged == null) { return; @@ -250,73 +229,6 @@ public static void removeTrusted(Plot plot, UUID uuid) { } } - /** - * @param cluster - * @param uuid - */ - public static void removeHelper(PlotCluster cluster, UUID uuid) { - if (cluster == null || uuid == null) { - return; - } - ClusterRepository clusterRepo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); - ClusterHelperRepository helperRepo = PlotSquared.platform().injector().getInstance(ClusterHelperRepository.class); - String world = cluster.area != null ? cluster.area.toString() : null; - PlotId center = cluster.getCenterPlotId(); - if (world != null) { - Optional ent = clusterRepo.findByWorldAndBounds(world, center.getX(), center.getY()); - if (ent.isPresent() && ent.get().getId() != null) { - helperRepo.remove(ent.get().getId(), uuid.toString()); - } - } - } - - /** - * @param cluster - */ - public static void createCluster(PlotCluster cluster) { - if (cluster == null) { - return; - } - ClusterRepository repo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); - ClusterEntity e = new ClusterEntity(); - e.setWorld(cluster.area != null ? cluster.area.toString() : null); - e.setOwner(cluster.owner != null ? cluster.owner.toString() : null); - if (cluster.getP1() != null) { - e.setPos1X(cluster.getP1().getX()); - e.setPos1Z(cluster.getP1().getY()); - } - if (cluster.getP2() != null) { - e.setPos2X(cluster.getP2().getX()); - e.setPos2Z(cluster.getP2().getY()); - } - repo.save(e); - } - - /** - * @param current - * @param min - * @param max - */ - public static void resizeCluster(PlotCluster current, PlotId min, PlotId max) { - if (current == null || min == null || max == null) { - return; - } - ClusterRepository repo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); - String world = current.area != null ? current.area.toString() : null; - PlotId center = current.getCenterPlotId(); - if (world != null) { - Optional ent = repo.findByWorldAndBounds(world, center.getX(), center.getY()); - if (ent.isPresent()) { - ClusterEntity e = ent.get(); - e.setPos1X(min.getX()); - e.setPos1Z(min.getY()); - e.setPos2X(max.getX()); - e.setPos2Z(max.getY()); - repo.save(e); - } - } - } - /** * @param plot * @param uuid @@ -330,22 +242,6 @@ public static void removeMember(Plot plot, UUID uuid) { pe.ifPresent(entity -> membershipRepo.remove(entity.getId(), uuid.toString())); } - /** - * @param cluster - * @param uuid - */ - public static void removeInvited(PlotCluster cluster, UUID uuid) { - ClusterRepository clusterRepo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); - ClusterInvitedRepository invitedRepo = PlotSquared.platform().injector().getInstance(ClusterInvitedRepository.class); - String world = cluster.area != null ? cluster.area.getWorldName() : null; - if (world == null) { - return; - } - PlotId center = cluster.getCenterPlotId(); - Optional ce = clusterRepo.findByWorldAndBounds(world, center.getX(), center.getY()); - ce.ifPresent(entity -> invitedRepo.remove(entity.getId(), uuid.toString())); - } - /** * @param plot * @param uuid @@ -359,18 +255,6 @@ public static void setTrusted(Plot plot, UUID uuid) { pe.ifPresent(entity -> trustedRepo.add(entity.getId(), uuid.toString())); } - public static void setHelper(PlotCluster cluster, UUID uuid) { - ClusterRepository clusterRepo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); - ClusterHelperRepository helperRepo = PlotSquared.platform().injector().getInstance(ClusterHelperRepository.class); - String world = cluster.area != null ? cluster.area.getWorldName() : null; - if (world == null) { - return; - } - PlotId center = cluster.getCenterPlotId(); - Optional ce = clusterRepo.findByWorldAndBounds(world, center.getX(), center.getY()); - ce.ifPresent(entity -> helperRepo.add(entity.getId(), uuid.toString())); - } - /** * @param plot * @param uuid @@ -384,18 +268,6 @@ public static void setMember(Plot plot, UUID uuid) { pe.ifPresent(entity -> membershipRepo.add(entity.getId(), uuid.toString())); } - public static void setInvited(PlotCluster cluster, UUID uuid) { - ClusterRepository clusterRepo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); - ClusterInvitedRepository invitedRepo = PlotSquared.platform().injector().getInstance(ClusterInvitedRepository.class); - String world = cluster.area != null ? cluster.area.getWorldName() : null; - if (world == null) { - return; - } - PlotId center = cluster.getCenterPlotId(); - Optional ce = clusterRepo.findByWorldAndBounds(world, center.getX(), center.getY()); - ce.ifPresent(entity -> invitedRepo.add(entity.getId(), uuid.toString())); - } - /** * @param plot * @param uuid @@ -454,73 +326,4 @@ public static void setRating(Plot plot, UUID rater, int value) { pe.ifPresent(entity -> ratingRepo.upsert(entity.getId(), rater.toString(), value)); } - public static HashMap> getClusters() { - HashMap> result = new HashMap<>(); - ClusterRepository clusterRepo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); - ClusterHelperRepository helperRepo = PlotSquared.platform().injector().getInstance(ClusterHelperRepository.class); - ClusterInvitedRepository invitedRepo = PlotSquared.platform().injector().getInstance(ClusterInvitedRepository.class); - ClusterSettingsRepository settingsRepo = PlotSquared.platform().injector().getInstance(ClusterSettingsRepository.class); - List clusters = clusterRepo.findAll(); - Map built = new HashMap<>(); - for (ClusterEntity ce : clusters) { - UUID owner = Optional.ofNullable(ce.getOwner()).map(UUID::fromString).orElse(null); - PlotCluster cluster = new PlotCluster(null, PlotId.of(ce.getPos1X(), ce.getPos1Z()), PlotId.of(ce.getPos2X(), ce.getPos2Z()), owner); - built.put(ce.getId(), cluster); - result.computeIfAbsent(ce.getWorld(), k -> new java.util.HashSet<>()).add(cluster); - } - // Populate helpers and invited - for (Map.Entry e : built.entrySet()) { - long id = e.getKey(); - PlotCluster cluster = e.getValue(); - for (String u : helperRepo.findUsers(id)) { - cluster.helpers.add(UUID.fromString(u)); - } - for (String u : invitedRepo.findUsers(id)) { - cluster.invited.add(UUID.fromString(u)); - } - // Apply settings (alias, merged). Avoid setting temp variable. - settingsRepo.findById(id).ifPresent(se -> { - if (se.getAlias() != null) { - cluster.settings.setAlias(se.getAlias()); - } - Integer m = se.getMerged(); - if (m != null) { - boolean[] merged = new boolean[4]; - for (int i = 0; i < 4; i++) { - merged[3 - i] = (m & 1 << i) != 0; - } - cluster.settings.setMerged(merged); - } - }); - } - return result; - } - - public static void setPosition(PlotCluster cluster, String position) { - if (cluster == null || position == null) { - return; - } - ClusterRepository clusterRepo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); - ClusterSettingsRepository settingsRepo = PlotSquared.platform().injector().getInstance(ClusterSettingsRepository.class); - String world = cluster.area != null ? cluster.area.getWorldName() : null; - if (world == null) { - return; - } - PlotId center = cluster.getCenterPlotId(); - Optional ce = clusterRepo.findByWorldAndBounds(world, center.getX(), center.getY()); - ce.ifPresent(entity -> settingsRepo.updatePosition(entity.getId(), position)); - } - - public static void replaceWorld(String oldWorld, String newWorld, PlotId min, PlotId max) { - PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - ClusterRepository clusterRepo = PlotSquared.platform().injector().getInstance(ClusterRepository.class); - if (min == null) { - plotRepo.replaceWorld(oldWorld, newWorld); - clusterRepo.replaceWorld(oldWorld, newWorld); - } else { - plotRepo.replaceWorldInBounds(oldWorld, newWorld, min, max); - clusterRepo.replaceWorldInBounds(oldWorld, newWorld, min, max); - } - } - } From 4d744dab21e68f53637cb49863f8ae78283b0a65 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 00:57:49 +0200 Subject: [PATCH 132/141] feat: remove unused DBFunc imports from Cluster and PlotSquared classes --- .../com/plotsquared/core/PlotSquared.java | 1 - .../com/plotsquared/core/command/Cluster.java | 1 - .../core/services/api/ClusterService.java | 18 ++++++++++++++++++ .../services/impl/ClusterDefaultService.java | 19 ++++++++++++++++++- 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/PlotSquared.java b/Core/src/main/java/com/plotsquared/core/PlotSquared.java index 1b825ef538..9f2b6cbd68 100644 --- a/Core/src/main/java/com/plotsquared/core/PlotSquared.java +++ b/Core/src/main/java/com/plotsquared/core/PlotSquared.java @@ -30,7 +30,6 @@ import com.plotsquared.core.configuration.caption.load.DefaultCaptionProvider; import com.plotsquared.core.configuration.file.YamlConfiguration; import com.plotsquared.core.configuration.serialization.ConfigurationSerialization; -import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.generator.GeneratorWrapper; import com.plotsquared.core.generator.HybridPlotWorld; import com.plotsquared.core.generator.HybridUtils; diff --git a/Core/src/main/java/com/plotsquared/core/command/Cluster.java b/Core/src/main/java/com/plotsquared/core/command/Cluster.java index 3a01a148c4..ab2c5df23b 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Cluster.java +++ b/Core/src/main/java/com/plotsquared/core/command/Cluster.java @@ -22,7 +22,6 @@ import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.caption.Caption; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.events.TeleportCause; import com.plotsquared.core.location.BlockLoc; import com.plotsquared.core.location.Location; diff --git a/Core/src/main/java/com/plotsquared/core/services/api/ClusterService.java b/Core/src/main/java/com/plotsquared/core/services/api/ClusterService.java index fe017f7407..647e901550 100644 --- a/Core/src/main/java/com/plotsquared/core/services/api/ClusterService.java +++ b/Core/src/main/java/com/plotsquared/core/services/api/ClusterService.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.services.api; import com.plotsquared.core.plot.PlotCluster; diff --git a/Core/src/main/java/com/plotsquared/core/services/impl/ClusterDefaultService.java b/Core/src/main/java/com/plotsquared/core/services/impl/ClusterDefaultService.java index 8dacff568c..0cda624458 100644 --- a/Core/src/main/java/com/plotsquared/core/services/impl/ClusterDefaultService.java +++ b/Core/src/main/java/com/plotsquared/core/services/impl/ClusterDefaultService.java @@ -1,6 +1,23 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.services.impl; -import com.plotsquared.core.PlotSquared; import com.plotsquared.core.persistence.entity.ClusterEntity; import com.plotsquared.core.persistence.repository.api.ClusterHelperRepository; import com.plotsquared.core.persistence.repository.api.ClusterInvitedRepository; From f1fd063b5b885f7eec51251b8a877fa5c59fe6d5 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 01:08:45 +0200 Subject: [PATCH 133/141] feat: refactor DBFunc methods to use PlotService for database operations --- .../com/plotsquared/core/command/Purge.java | 3 +- .../com/plotsquared/core/database/DBFunc.java | 57 ------------------- .../java/com/plotsquared/core/plot/Plot.java | 15 ++--- .../core/services/api/PlotService.java | 12 ++++ .../services/impl/PlotDefaultService.java | 44 +++++++++++++- 5 files changed, 65 insertions(+), 66 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/command/Purge.java b/Core/src/main/java/com/plotsquared/core/command/Purge.java index 873c732b93..69f88bddab 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Purge.java +++ b/Core/src/main/java/com/plotsquared/core/command/Purge.java @@ -29,6 +29,7 @@ import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotId; import com.plotsquared.core.plot.world.PlotAreaManager; +import com.plotsquared.core.services.api.PlotService; import com.plotsquared.core.util.StringMan; import com.plotsquared.core.util.query.PlotQuery; import com.plotsquared.core.util.task.TaskManager; @@ -241,7 +242,7 @@ public void run() { TaskManager.runTaskAsync(this); } else { TaskManager.runTask(() -> { - DBFunc.purgeIds(ids); + PlotSquared.platform().injector().getInstance(PlotService.class).purgeIds(ids); player.sendMessage( TranslatableCaption.of("purge.purge_success"), TagResolver.resolver( diff --git a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java index 747098f737..b15029c443 100644 --- a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java +++ b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java @@ -28,10 +28,8 @@ import com.plotsquared.core.persistence.repository.api.PlotMembershipRepository; import com.plotsquared.core.persistence.repository.api.PlotRatingRepository; import com.plotsquared.core.persistence.repository.api.PlotRepository; -import com.plotsquared.core.persistence.repository.api.PlotSettingsRepository; import com.plotsquared.core.persistence.repository.api.PlotTrustedRepository; import com.plotsquared.core.plot.Plot; -import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotId; import com.plotsquared.core.plot.comment.PlotComment; import com.plotsquared.core.plot.flag.PlotFlag; @@ -41,7 +39,6 @@ import java.util.HashMap; import java.util.List; import java.util.Optional; -import java.util.Set; import java.util.UUID; /** @@ -57,22 +54,6 @@ public class DBFunc { public static final UUID EVERYONE = UUID.fromString("1-1-3-3-7"); public static final UUID SERVER = UUID.fromString("00000000-0000-0000-0000-000000000000"); - public static void setMerged(Plot plot, boolean[] merged) { - if (plot == null || merged == null) { - return; - } - PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - PlotSettingsRepository settingsRepo = PlotSquared.platform().injector().getInstance(PlotSettingsRepository.class); - String world = plot.getWorldName(); - int x = plot.getId().getX(); - int z = plot.getId().getY(); - Optional pe = plotRepo.findByWorldAndId(world, x, z); - pe.ifPresent(entity -> { - int mask = com.plotsquared.core.util.HashUtil.hash(merged); - settingsRepo.updateMerged(entity.getId(), mask); - }); - } - public static void setFlag(Plot plot, PlotFlag flag) { if (plot == null || flag == null) { return; @@ -111,44 +92,6 @@ public static void removeFlag(Plot plot, PlotFlag flag) { pe.ifPresent(entity -> flagRepo.deleteByPlotAndName(entity.getId(), flag.getName())); } - /** - * @param plot - * @param alias - */ - public static void setAlias(Plot plot, String alias) { - if (plot == null) { - return; - } - PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - PlotSettingsRepository settingsRepo = PlotSquared.platform().injector().getInstance(PlotSettingsRepository.class); - Optional pe = plotRepo.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); - pe.ifPresent(entity -> settingsRepo.updateAlias(entity.getId(), alias)); - } - - public static void purgeIds(Set uniqueIds) { - PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - plotRepo.purgeIds(uniqueIds); - } - - public static void purge(PlotArea area, Set plotIds) { - PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - plotRepo.purgeByWorldAndPlotIds(area.getWorldName(), plotIds); - } - - /** - * @param plot - * @param position - */ - public static void setPosition(Plot plot, String position) { - if (plot == null || position == null) { - return; - } - PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - PlotSettingsRepository settingsRepo = PlotSquared.platform().injector().getInstance(PlotSettingsRepository.class); - Optional pe = plotRepo.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); - pe.ifPresent(entity -> settingsRepo.updatePosition(entity.getId(), position)); - } - /** * @param plot * @param comment diff --git a/Core/src/main/java/com/plotsquared/core/plot/Plot.java b/Core/src/main/java/com/plotsquared/core/plot/Plot.java index 5fb0b9b120..23757ca31b 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/Plot.java +++ b/Core/src/main/java/com/plotsquared/core/plot/Plot.java @@ -1552,10 +1552,11 @@ public void setHome(BlockLoc location) { } plot.getSettings().setPosition(location); if (location != null) { - DBFunc.setPosition(plot, plot.getSettings().getPosition().toString()); + PlotSquared.platform().injector().getInstance(PlotService.class).setPosition(plot, + plot.getSettings().getPosition().toString()); return; } - DBFunc.setPosition(plot, null); + PlotSquared.platform().injector().getInstance(PlotService.class).setPosition(plot, null); } /** @@ -2171,7 +2172,7 @@ public void setAlias(String alias) { return; } current.getSettings().setAlias(alias); - DBFunc.setAlias(current, alias); + PlotSquared.platform().injector().getInstance(PlotService.class).setAlias(current, alias); } } @@ -2204,7 +2205,7 @@ public void setMerged(Direction direction, boolean value) { } this.connectedCache = null; } - DBFunc.setMerged(this, this.getSettings().getMerged()); + PlotSquared.platform().injector().getInstance(PlotService.class).setMerged(this, this.getSettings().getMerged()); } } @@ -2234,7 +2235,7 @@ public boolean[] getMerged() { */ public void setMerged(boolean[] merged) { this.getSettings().setMerged(merged); - DBFunc.setMerged(this, merged); + PlotSquared.platform().injector().getInstance(PlotService.class).setMerged(this, merged); clearCache(); } @@ -2413,10 +2414,10 @@ private void computeDirectMerged(Set queueCache, Deque frontier, Dir // invalid merge if (tmp.isOwnerAbs(this.getOwnerAbs())) { tmp.getSettings().setMerged(direction.opposite(), true); - DBFunc.setMerged(tmp, tmp.getSettings().getMerged()); + PlotSquared.platform().injector().getInstance(PlotService.class).setMerged(tmp, tmp.getSettings().getMerged()); } else { this.getSettings().setMerged(direction, false); - DBFunc.setMerged(this, this.getSettings().getMerged()); + PlotSquared.platform().injector().getInstance(PlotService.class).setMerged(this, this.getSettings().getMerged()); } } queueCache.add(tmp); diff --git a/Core/src/main/java/com/plotsquared/core/services/api/PlotService.java b/Core/src/main/java/com/plotsquared/core/services/api/PlotService.java index 94ea50260a..227810dbc3 100644 --- a/Core/src/main/java/com/plotsquared/core/services/api/PlotService.java +++ b/Core/src/main/java/com/plotsquared/core/services/api/PlotService.java @@ -19,10 +19,12 @@ package com.plotsquared.core.services.api; import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotId; import java.util.HashMap; import java.util.List; +import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -50,4 +52,14 @@ void createPlotSafe( HashMap> getPlots(); + void setMerged(Plot plot, boolean[] merged); + + void setAlias(Plot plot, String alias); + + void setPosition(Plot plot, String position); + + void purgeIds(Set uniqueIds); + + void purge(PlotArea area, Set plotIds); + } diff --git a/Core/src/main/java/com/plotsquared/core/services/impl/PlotDefaultService.java b/Core/src/main/java/com/plotsquared/core/services/impl/PlotDefaultService.java index 71287ffdc1..90acf2733c 100644 --- a/Core/src/main/java/com/plotsquared/core/services/impl/PlotDefaultService.java +++ b/Core/src/main/java/com/plotsquared/core/services/impl/PlotDefaultService.java @@ -18,8 +18,12 @@ */ package com.plotsquared.core.services.impl; +import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.persistence.entity.PlotEntity; import com.plotsquared.core.persistence.repository.api.PlotRepository; +import com.plotsquared.core.persistence.repository.api.PlotSettingsRepository; import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotId; import com.plotsquared.core.services.api.PlotService; import jakarta.inject.Inject; @@ -27,16 +31,20 @@ import java.util.HashMap; import java.util.List; +import java.util.Optional; +import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; public class PlotDefaultService implements PlotService { private final PlotRepository repository; + private final PlotSettingsRepository settingsRepository; @Inject - public PlotDefaultService(final PlotRepository repository) { + public PlotDefaultService(final PlotRepository repository, final PlotSettingsRepository settingsRepository) { this.repository = repository; + this.settingsRepository = settingsRepository; } @Override @@ -91,4 +99,38 @@ public HashMap> getPlots() { return this.repository.getPlots(); } + @Override + public void setMerged(final Plot plot, final boolean[] merged) { + String world = plot.getWorldName(); + int x = plot.getId().getX(); + int z = plot.getId().getY(); + Optional pe = this.repository.findByWorldAndId(world, x, z); + pe.ifPresent(entity -> { + int mask = com.plotsquared.core.util.HashUtil.hash(merged); + this.settingsRepository.updateMerged(entity.getId(), mask); + }); + } + + @Override + public void setAlias(final Plot plot, final String alias) { + Optional pe = this.repository.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); + pe.ifPresent(entity -> this.settingsRepository.updateAlias(entity.getId(), alias)); + } + + @Override + public void setPosition(final Plot plot, final String position) { + Optional pe = this.repository.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); + pe.ifPresent(entity -> this.settingsRepository.updatePosition(entity.getId(), position)); + } + + @Override + public void purgeIds(final Set uniqueIds) { + this.repository.purgeIds(uniqueIds); + } + + @Override + public void purge(final PlotArea area, final Set plotIds) { + this.repository.purgeByWorldAndPlotIds(area.getWorldName(), plotIds); + } + } From 895ca03b8068c839e3c6f0ed1c328e88038955e3 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 01:09:13 +0200 Subject: [PATCH 134/141] feat: remove unused imports from Purge and PlotDefaultService classes --- Core/src/main/java/com/plotsquared/core/command/Purge.java | 1 - .../com/plotsquared/core/services/impl/PlotDefaultService.java | 1 - 2 files changed, 2 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/command/Purge.java b/Core/src/main/java/com/plotsquared/core/command/Purge.java index 69f88bddab..bc8bfa055e 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Purge.java +++ b/Core/src/main/java/com/plotsquared/core/command/Purge.java @@ -22,7 +22,6 @@ import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.listener.PlotListener; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; diff --git a/Core/src/main/java/com/plotsquared/core/services/impl/PlotDefaultService.java b/Core/src/main/java/com/plotsquared/core/services/impl/PlotDefaultService.java index 90acf2733c..7b62ae7934 100644 --- a/Core/src/main/java/com/plotsquared/core/services/impl/PlotDefaultService.java +++ b/Core/src/main/java/com/plotsquared/core/services/impl/PlotDefaultService.java @@ -18,7 +18,6 @@ */ package com.plotsquared.core.services.impl; -import com.plotsquared.core.PlotSquared; import com.plotsquared.core.persistence.entity.PlotEntity; import com.plotsquared.core.persistence.repository.api.PlotRepository; import com.plotsquared.core.persistence.repository.api.PlotSettingsRepository; From 0432dcf1a8f4529d77e59e8923659a79b1ce2102 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 01:25:27 +0200 Subject: [PATCH 135/141] feat: refactor flag management by introducing FlagService and removing DBFunc methods --- .../com/plotsquared/core/database/DBFunc.java | 38 ------------- .../java/com/plotsquared/core/plot/Plot.java | 5 +- .../core/plot/PlotModificationManager.java | 5 +- .../core/services/api/FlagService.java | 11 ++++ .../core/services/config/ServiceModule.java | 3 + .../services/impl/FlagDefaultService.java | 57 +++++++++++++++++++ 6 files changed, 77 insertions(+), 42 deletions(-) create mode 100644 Core/src/main/java/com/plotsquared/core/services/api/FlagService.java create mode 100644 Core/src/main/java/com/plotsquared/core/services/impl/FlagDefaultService.java diff --git a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java index b15029c443..f8fa02ea2e 100644 --- a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java +++ b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java @@ -54,44 +54,6 @@ public class DBFunc { public static final UUID EVERYONE = UUID.fromString("1-1-3-3-7"); public static final UUID SERVER = UUID.fromString("00000000-0000-0000-0000-000000000000"); - public static void setFlag(Plot plot, PlotFlag flag) { - if (plot == null || flag == null) { - return; - } - PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - PlotFlagRepository flagRepo = PlotSquared.platform().injector().getInstance(PlotFlagRepository.class); - Optional pe = plotRepo.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); - pe.ifPresent(entity -> { - long plotId = entity.getId(); - String name = flag.getName(); - String value = flag.toString(); - var existing = flagRepo.findByPlotAndName(plotId, name); - if (existing.isPresent()) { - var e = existing.get(); - e.setFlagValue(value); - flagRepo.save(e); - } else { - PlotFlagEntity e = new PlotFlagEntity(); - PlotEntity pref = new PlotEntity(); - pref.setId(entity.getId()); - e.setPlot(pref); - e.setFlag(name); - e.setFlagValue(value); - flagRepo.save(e); - } - }); - } - - public static void removeFlag(Plot plot, PlotFlag flag) { - if (plot == null || flag == null) { - return; - } - PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - PlotFlagRepository flagRepo = PlotSquared.platform().injector().getInstance(PlotFlagRepository.class); - Optional pe = plotRepo.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); - pe.ifPresent(entity -> flagRepo.deleteByPlotAndName(entity.getId(), flag.getName())); - } - /** * @param plot * @param comment diff --git a/Core/src/main/java/com/plotsquared/core/plot/Plot.java b/Core/src/main/java/com/plotsquared/core/plot/Plot.java index 23757ca31b..72b892af12 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/Plot.java +++ b/Core/src/main/java/com/plotsquared/core/plot/Plot.java @@ -53,6 +53,7 @@ import com.plotsquared.core.plot.schematic.Schematic; import com.plotsquared.core.plot.world.SinglePlotArea; import com.plotsquared.core.queue.QueueCoordinator; +import com.plotsquared.core.services.api.FlagService; import com.plotsquared.core.services.api.PlotService; import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.MathMan; @@ -1171,7 +1172,7 @@ public boolean setFlag(final @NonNull PlotFlag flag) { for (final Plot plot : this.getConnectedPlots()) { plot.getFlagContainer().addFlag(flag); plot.reEnter(); - DBFunc.setFlag(plot, flag); + PlotSquared.platform().injector().getInstance(FlagService.class).setFlag(plot, flag); } return true; } @@ -1261,7 +1262,7 @@ public boolean removeFlag(final @NonNull PlotFlag flag) { continue; } plot.reEnter(); - DBFunc.removeFlag(plot, flag); + PlotSquared.platform().injector().getInstance(FlagService.class).removeFlag(plot, flag); removed = true; } return removed; diff --git a/Core/src/main/java/com/plotsquared/core/plot/PlotModificationManager.java b/Core/src/main/java/com/plotsquared/core/plot/PlotModificationManager.java index 49802c7f1a..102fa0aa7b 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/PlotModificationManager.java +++ b/Core/src/main/java/com/plotsquared/core/plot/PlotModificationManager.java @@ -38,6 +38,7 @@ import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.flag.PlotFlag; import com.plotsquared.core.queue.QueueCoordinator; +import com.plotsquared.core.services.api.FlagService; import com.plotsquared.core.services.api.PlotService; import com.plotsquared.core.util.task.TaskManager; import com.plotsquared.core.util.task.TaskTime; @@ -125,9 +126,9 @@ public CompletableFuture copy(final @NonNull Plot destination, @Nullabl for (final PlotFlag flag : existingFlags) { final PlotFlag newFlag = other.getFlagContainer().queryLocal(flag.getClass()); if (other.getFlagContainer().queryLocal(flag.getClass()) == null) { - DBFunc.removeFlag(other, flag); + PlotSquared.platform().injector().getInstance(FlagService.class).removeFlag(other, flag); } else { - DBFunc.setFlag(other, newFlag); + PlotSquared.platform().injector().getInstance(FlagService.class).setFlag(other, newFlag); } } } diff --git a/Core/src/main/java/com/plotsquared/core/services/api/FlagService.java b/Core/src/main/java/com/plotsquared/core/services/api/FlagService.java new file mode 100644 index 0000000000..9d0320aa93 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/api/FlagService.java @@ -0,0 +1,11 @@ +package com.plotsquared.core.services.api; + +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.flag.PlotFlag; + +public interface FlagService { + + void setFlag(Plot plot, PlotFlag flag); + + void removeFlag(Plot plot, PlotFlag flag); +} diff --git a/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java b/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java index 0855f13120..b121d8a20f 100644 --- a/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java +++ b/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java @@ -20,9 +20,11 @@ import com.google.inject.AbstractModule; import com.plotsquared.core.services.api.ClusterService; +import com.plotsquared.core.services.api.FlagService; import com.plotsquared.core.services.api.PlayerMetaService; import com.plotsquared.core.services.api.PlotService; import com.plotsquared.core.services.impl.ClusterDefaultService; +import com.plotsquared.core.services.impl.FlagDefaultService; import com.plotsquared.core.services.impl.PlayerMetaDefaultService; import com.plotsquared.core.services.impl.PlotDefaultService; @@ -33,6 +35,7 @@ protected void configure() { bind(PlayerMetaService.class).to(PlayerMetaDefaultService.class); bind(PlotService.class).to(PlotDefaultService.class); bind(ClusterService.class).to(ClusterDefaultService.class); + bind(FlagService.class).to(FlagDefaultService.class); } } diff --git a/Core/src/main/java/com/plotsquared/core/services/impl/FlagDefaultService.java b/Core/src/main/java/com/plotsquared/core/services/impl/FlagDefaultService.java new file mode 100644 index 0000000000..1cf6206a9b --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/impl/FlagDefaultService.java @@ -0,0 +1,57 @@ +package com.plotsquared.core.services.impl; + +import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.persistence.entity.PlotEntity; +import com.plotsquared.core.persistence.entity.PlotFlagEntity; +import com.plotsquared.core.persistence.repository.api.PlotFlagRepository; +import com.plotsquared.core.persistence.repository.api.PlotRepository; +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.flag.PlotFlag; +import com.plotsquared.core.services.api.FlagService; +import jakarta.inject.Inject; + +import java.util.Optional; + +public class FlagDefaultService implements FlagService { + + private final PlotRepository plotRepository; + private final PlotFlagRepository flagRepository; + + @Inject + public FlagDefaultService(final PlotRepository repository, final PlotFlagRepository flagRepository) { + this.plotRepository = repository; + this.flagRepository = flagRepository; + } + + @Override + public void setFlag(final Plot plot, final PlotFlag flag) { + Optional pe = this.plotRepository.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); + pe.ifPresent(entity -> { + long plotId = entity.getId(); + String name = flag.getName(); + String value = flag.toString(); + var existing = this.flagRepository.findByPlotAndName(plotId, name); + if (existing.isPresent()) { + var e = existing.get(); + e.setFlagValue(value); + this.flagRepository.save(e); + } else { + PlotFlagEntity e = new PlotFlagEntity(); + PlotEntity pref = new PlotEntity(); + pref.setId(entity.getId()); + e.setPlot(pref); + e.setFlag(name); + e.setFlagValue(value); + this.flagRepository.save(e); + } + }); + } + + @Override + public void removeFlag(final Plot plot, final PlotFlag flag) { + Optional pe = this.plotRepository.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), + plot.getId().getY()); + pe.ifPresent(entity -> this.flagRepository.deleteByPlotAndName(entity.getId(), flag.getName())); + } + +} From c6e769b844b953599a92c99bbaf3e30fb219fee4 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 01:26:27 +0200 Subject: [PATCH 136/141] feat: add FlagService and FlagDefaultService with necessary imports and licensing --- .../com/plotsquared/core/database/DBFunc.java | 3 --- .../core/services/api/FlagService.java | 18 ++++++++++++++++++ .../services/impl/FlagDefaultService.java | 19 ++++++++++++++++++- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java index f8fa02ea2e..90469179a3 100644 --- a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java +++ b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java @@ -21,10 +21,8 @@ import com.plotsquared.core.PlotSquared; import com.plotsquared.core.persistence.entity.PlotCommentEntity; import com.plotsquared.core.persistence.entity.PlotEntity; -import com.plotsquared.core.persistence.entity.PlotFlagEntity; import com.plotsquared.core.persistence.repository.api.PlotCommentRepository; import com.plotsquared.core.persistence.repository.api.PlotDeniedRepository; -import com.plotsquared.core.persistence.repository.api.PlotFlagRepository; import com.plotsquared.core.persistence.repository.api.PlotMembershipRepository; import com.plotsquared.core.persistence.repository.api.PlotRatingRepository; import com.plotsquared.core.persistence.repository.api.PlotRepository; @@ -32,7 +30,6 @@ import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotId; import com.plotsquared.core.plot.comment.PlotComment; -import com.plotsquared.core.plot.flag.PlotFlag; import com.plotsquared.core.util.task.RunnableVal; import java.util.ArrayList; diff --git a/Core/src/main/java/com/plotsquared/core/services/api/FlagService.java b/Core/src/main/java/com/plotsquared/core/services/api/FlagService.java index 9d0320aa93..dbb566057f 100644 --- a/Core/src/main/java/com/plotsquared/core/services/api/FlagService.java +++ b/Core/src/main/java/com/plotsquared/core/services/api/FlagService.java @@ -1,3 +1,21 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.services.api; import com.plotsquared.core.plot.Plot; diff --git a/Core/src/main/java/com/plotsquared/core/services/impl/FlagDefaultService.java b/Core/src/main/java/com/plotsquared/core/services/impl/FlagDefaultService.java index 1cf6206a9b..a4f325334b 100644 --- a/Core/src/main/java/com/plotsquared/core/services/impl/FlagDefaultService.java +++ b/Core/src/main/java/com/plotsquared/core/services/impl/FlagDefaultService.java @@ -1,6 +1,23 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.plotsquared.core.services.impl; -import com.plotsquared.core.PlotSquared; import com.plotsquared.core.persistence.entity.PlotEntity; import com.plotsquared.core.persistence.entity.PlotFlagEntity; import com.plotsquared.core.persistence.repository.api.PlotFlagRepository; From 5d64771cd42492e74359a5569e6d42573d4cb91d Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 01:35:42 +0200 Subject: [PATCH 137/141] feat: refactor comment handling by introducing CommentService and removing DBFunc methods --- .../com/plotsquared/core/database/DBFunc.java | 67 -------------- .../core/plot/comment/CommentInbox.java | 7 +- .../core/plot/comment/InboxOwner.java | 23 ++--- .../core/plot/comment/InboxPublic.java | 20 ++--- .../core/plot/comment/InboxReport.java | 14 ++- .../core/services/api/CommentService.java | 36 ++++++++ .../core/services/config/ServiceModule.java | 3 + .../services/impl/CommentDefaultService.java | 88 +++++++++++++++++++ 8 files changed, 153 insertions(+), 105 deletions(-) create mode 100644 Core/src/main/java/com/plotsquared/core/services/api/CommentService.java create mode 100644 Core/src/main/java/com/plotsquared/core/services/impl/CommentDefaultService.java diff --git a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java index 90469179a3..85f5295095 100644 --- a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java +++ b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java @@ -19,9 +19,7 @@ package com.plotsquared.core.database; import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.persistence.entity.PlotCommentEntity; import com.plotsquared.core.persistence.entity.PlotEntity; -import com.plotsquared.core.persistence.repository.api.PlotCommentRepository; import com.plotsquared.core.persistence.repository.api.PlotDeniedRepository; import com.plotsquared.core.persistence.repository.api.PlotMembershipRepository; import com.plotsquared.core.persistence.repository.api.PlotRatingRepository; @@ -29,12 +27,8 @@ import com.plotsquared.core.persistence.repository.api.PlotTrustedRepository; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotId; -import com.plotsquared.core.plot.comment.PlotComment; -import com.plotsquared.core.util.task.RunnableVal; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Optional; import java.util.UUID; @@ -51,67 +45,6 @@ public class DBFunc { public static final UUID EVERYONE = UUID.fromString("1-1-3-3-7"); public static final UUID SERVER = UUID.fromString("00000000-0000-0000-0000-000000000000"); - /** - * @param plot - * @param comment - */ - public static void removeComment(Plot plot, PlotComment comment) { - PlotCommentRepository repo = PlotSquared.platform().injector().getInstance(PlotCommentRepository.class); - String world = plot.getWorldName(); - int hash = plot.getId().hashCode(); - repo.deleteOne(world, hash, comment.inbox(), comment.senderName(), comment.comment()); - } - - public static void clearInbox(Plot plot, String inbox) { - PlotCommentRepository repo = PlotSquared.platform().injector().getInstance(PlotCommentRepository.class); - if (plot != null) { - String world = plot.getWorldName(); - int hash = plot.getId().hashCode(); - repo.clearInbox(world, hash, inbox); - } - } - - /** - * @param plot - * @param comment - */ - public static void setComment(Plot plot, PlotComment comment) { - PlotCommentRepository repo = PlotSquared.platform().injector().getInstance(PlotCommentRepository.class); - if (plot != null) { - PlotCommentEntity entity = new PlotCommentEntity(); - entity.setWorld(plot.getWorldName()); - entity.setHashcode(plot.getId().hashCode()); - entity.setComment(comment.comment()); - entity.setInbox(comment.inbox()); - entity.setTimestamp((int) (comment.timestamp() / 1000)); - entity.setSender(comment.senderName()); - repo.save(entity); - } - } - - /** - * @param plot - */ - public static void getComments( - Plot plot, String inbox, - RunnableVal> whenDone - ) { - PlotCommentRepository repo = PlotSquared.platform().injector().getInstance(PlotCommentRepository.class); - List out = new ArrayList<>(); - if (plot != null) { - String world = plot.getWorldName(); - int hash = plot.getId().hashCode(); - for (PlotCommentEntity e : repo.findByWorldHashAndInbox(world, hash, inbox)) { - PlotId id = (e.getHashcode() != null && e.getHashcode() != 0) ? PlotId.unpair(e.getHashcode()) : null; - long tsMillis = e.getTimestamp() != null ? e.getTimestamp().longValue() * 1000L : 0L; - out.add(new PlotComment(e.getWorld(), id, e.getComment(), e.getSender(), e.getInbox(), tsMillis)); - } - } - if (whenDone != null) { - whenDone.run(out); - } - } - /** * @param plot * @param uuid diff --git a/Core/src/main/java/com/plotsquared/core/plot/comment/CommentInbox.java b/Core/src/main/java/com/plotsquared/core/plot/comment/CommentInbox.java index 1e0894538f..c10a47f79f 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/comment/CommentInbox.java +++ b/Core/src/main/java/com/plotsquared/core/plot/comment/CommentInbox.java @@ -18,9 +18,10 @@ */ package com.plotsquared.core.plot.comment; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.PlotSquared; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.services.api.CommentService; import com.plotsquared.core.util.task.RunnableVal; import java.util.List; @@ -91,14 +92,14 @@ public boolean canModify(Plot plot, PlotPlayer player) { * @param comment the comment to remove */ public void removeComment(Plot plot, PlotComment comment) { - DBFunc.removeComment(plot, comment); + PlotSquared.platform().injector().getInstance(CommentService.class).removeComment(plot, comment); } /** * @param plot plot */ public void clearInbox(Plot plot) { - DBFunc.clearInbox(plot, toString()); + PlotSquared.platform().injector().getInstance(CommentService.class).clearInbox(plot, toString()); } } diff --git a/Core/src/main/java/com/plotsquared/core/plot/comment/InboxOwner.java b/Core/src/main/java/com/plotsquared/core/plot/comment/InboxOwner.java index f872d32f4a..08bce323e6 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/comment/InboxOwner.java +++ b/Core/src/main/java/com/plotsquared/core/plot/comment/InboxOwner.java @@ -18,12 +18,12 @@ */ package com.plotsquared.core.plot.comment; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.PlotSquared; import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.services.api.CommentService; import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.TaskManager; -import java.util.ArrayList; import java.util.List; public class InboxOwner extends CommentInbox { @@ -36,19 +36,12 @@ public boolean getComments(final Plot plot, final RunnableVal> TaskManager.runTask(whenDone); return true; } - DBFunc.getComments(plot, toString(), new RunnableVal<>() { - @Override - public void run(List value) { - whenDone.value = value; - if (value != null) { - for (PlotComment comment : value) { - plot.getPlotCommentContainer().addComment(comment); - } - } else { - plot.getPlotCommentContainer().setComments(new ArrayList<>()); - } - TaskManager.runTask(whenDone); + PlotSquared.platform().injector().getInstance(CommentService.class).getComments(plot, toString(), value -> { + whenDone.value = value; + for (PlotComment comment : value) { + plot.getPlotCommentContainer().addComment(comment); } + TaskManager.runTask(whenDone); }); return true; } @@ -59,7 +52,7 @@ public boolean addComment(Plot plot, PlotComment comment) { return false; } plot.getPlotCommentContainer().addComment(comment); - DBFunc.setComment(plot, comment); + PlotSquared.platform().injector().getInstance(CommentService.class).setComment(plot, comment); return true; } diff --git a/Core/src/main/java/com/plotsquared/core/plot/comment/InboxPublic.java b/Core/src/main/java/com/plotsquared/core/plot/comment/InboxPublic.java index 53484e9cab..22323c18d0 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/comment/InboxPublic.java +++ b/Core/src/main/java/com/plotsquared/core/plot/comment/InboxPublic.java @@ -18,8 +18,9 @@ */ package com.plotsquared.core.plot.comment; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.PlotSquared; import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.services.api.CommentService; import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.TaskManager; @@ -35,17 +36,12 @@ public boolean getComments(final Plot plot, final RunnableVal> TaskManager.runTask(whenDone); return true; } - DBFunc.getComments(plot, toString(), new RunnableVal<>() { - @Override - public void run(List value) { - whenDone.value = value; - if (value != null) { - for (PlotComment comment : value) { - plot.getPlotCommentContainer().addComment(comment); - } - } - TaskManager.runTask(whenDone); + PlotSquared.platform().injector().getInstance(CommentService.class).getComments(plot, toString(), value -> { + whenDone.value = value; + for (PlotComment comment : value) { + plot.getPlotCommentContainer().addComment(comment); } + TaskManager.runTask(whenDone); }); return true; } @@ -53,7 +49,7 @@ public void run(List value) { @Override public boolean addComment(Plot plot, PlotComment comment) { plot.getPlotCommentContainer().addComment(comment); - DBFunc.setComment(plot, comment); + PlotSquared.platform().injector().getInstance(CommentService.class).setComment(plot, comment); return true; } diff --git a/Core/src/main/java/com/plotsquared/core/plot/comment/InboxReport.java b/Core/src/main/java/com/plotsquared/core/plot/comment/InboxReport.java index c8c5cc07fb..81007f1c4b 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/comment/InboxReport.java +++ b/Core/src/main/java/com/plotsquared/core/plot/comment/InboxReport.java @@ -18,8 +18,9 @@ */ package com.plotsquared.core.plot.comment; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.PlotSquared; import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.services.api.CommentService; import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.TaskManager; @@ -29,12 +30,9 @@ public class InboxReport extends CommentInbox { @Override public boolean getComments(Plot plot, final RunnableVal> whenDone) { - DBFunc.getComments(plot, toString(), new RunnableVal<>() { - @Override - public void run(List value) { - whenDone.value = value; - TaskManager.runTask(whenDone); - } + PlotSquared.platform().injector().getInstance(CommentService.class).getComments(plot, toString(), value -> { + whenDone.value = value; + TaskManager.runTask(whenDone); }); return true; } @@ -44,7 +42,7 @@ public boolean addComment(Plot plot, PlotComment comment) { if (plot.getOwner() == null) { return false; } - DBFunc.setComment(plot, comment); + PlotSquared.platform().injector().getInstance(CommentService.class).setComment(plot, comment); return true; } diff --git a/Core/src/main/java/com/plotsquared/core/services/api/CommentService.java b/Core/src/main/java/com/plotsquared/core/services/api/CommentService.java new file mode 100644 index 0000000000..6232bf390e --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/api/CommentService.java @@ -0,0 +1,36 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.services.api; + +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.comment.PlotComment; + +import java.util.List; +import java.util.function.Consumer; + +public interface CommentService { + + void removeComment(Plot plot, PlotComment comment); + + void setComment(Plot plot, PlotComment comment); + + void clearInbox(Plot plot, String inbox); + + void getComments(Plot plot, String inbox, Consumer> whenDone); +} diff --git a/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java b/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java index b121d8a20f..d1b41243e3 100644 --- a/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java +++ b/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java @@ -20,10 +20,12 @@ import com.google.inject.AbstractModule; import com.plotsquared.core.services.api.ClusterService; +import com.plotsquared.core.services.api.CommentService; import com.plotsquared.core.services.api.FlagService; import com.plotsquared.core.services.api.PlayerMetaService; import com.plotsquared.core.services.api.PlotService; import com.plotsquared.core.services.impl.ClusterDefaultService; +import com.plotsquared.core.services.impl.CommentDefaultService; import com.plotsquared.core.services.impl.FlagDefaultService; import com.plotsquared.core.services.impl.PlayerMetaDefaultService; import com.plotsquared.core.services.impl.PlotDefaultService; @@ -36,6 +38,7 @@ protected void configure() { bind(PlotService.class).to(PlotDefaultService.class); bind(ClusterService.class).to(ClusterDefaultService.class); bind(FlagService.class).to(FlagDefaultService.class); + bind(CommentService.class).to(CommentDefaultService.class); } } diff --git a/Core/src/main/java/com/plotsquared/core/services/impl/CommentDefaultService.java b/Core/src/main/java/com/plotsquared/core/services/impl/CommentDefaultService.java new file mode 100644 index 0000000000..7d359fb84f --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/impl/CommentDefaultService.java @@ -0,0 +1,88 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.services.impl; + +import com.plotsquared.core.persistence.entity.PlotCommentEntity; +import com.plotsquared.core.persistence.repository.api.PlotCommentRepository; +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.PlotId; +import com.plotsquared.core.plot.comment.PlotComment; +import com.plotsquared.core.services.api.CommentService; +import jakarta.inject.Inject; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +public class CommentDefaultService implements CommentService { + + private final PlotCommentRepository repository; + + @Inject + public CommentDefaultService(final PlotCommentRepository repository) { + this.repository = repository; + } + + @Override + public void removeComment(final Plot plot, final PlotComment comment) { + String world = plot.getWorldName(); + if (world == null) { + return; + } + int hash = plot.getId().hashCode(); + this.repository.deleteOne(world, hash, comment.inbox(), comment.senderName(), comment.comment()); + } + + @Override + public void setComment(final Plot plot, final PlotComment comment) { + PlotCommentEntity entity = new PlotCommentEntity(); + entity.setWorld(plot.getWorldName()); + entity.setHashcode(plot.getId().hashCode()); + entity.setComment(comment.comment()); + entity.setInbox(comment.inbox()); + entity.setTimestamp((int) (comment.timestamp() / 1000)); + entity.setSender(comment.senderName()); + this.repository.save(entity); + } + + @Override + public void clearInbox(final Plot plot, final String inbox) { + String world = plot.getWorldName(); + if (world == null) { + return; + } + int hash = plot.getId().hashCode(); + this.repository.clearInbox(world, hash, inbox); + } + + @Override + public void getComments(final Plot plot, final @NotNull String inbox, final @NotNull Consumer> whenDone) { + List out = new ArrayList<>(); + String world = plot.getWorldName(); + int hash = plot.getId().hashCode(); + for (PlotCommentEntity e : this.repository.findByWorldHashAndInbox(world, hash, inbox)) { + PlotId id = (e.getHashcode() != null && e.getHashcode() != 0) ? PlotId.unpair(e.getHashcode()) : null; + long tsMillis = e.getTimestamp() != null ? e.getTimestamp().longValue() * 1000L : 0L; + out.add(new PlotComment(e.getWorld(), id, e.getComment(), e.getSender(), e.getInbox(), tsMillis)); + } + whenDone.accept(out); + } + +} From 5d4bbe9ef5e928048bce13de624ad7df65cf8857 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 01:49:12 +0200 Subject: [PATCH 138/141] feat: introduce MemberService and refactor DBFunc methods for member management --- .../com/plotsquared/core/database/DBFunc.java | 91 ------------ .../java/com/plotsquared/core/plot/Plot.java | 13 +- .../core/plot/PlotModificationManager.java | 8 +- .../core/services/api/MemberService.java | 38 +++++ .../core/services/config/ServiceModule.java | 3 + .../services/impl/MemberDefaultService.java | 136 ++++++++++++++++++ 6 files changed, 188 insertions(+), 101 deletions(-) create mode 100644 Core/src/main/java/com/plotsquared/core/services/api/MemberService.java create mode 100644 Core/src/main/java/com/plotsquared/core/services/impl/MemberDefaultService.java diff --git a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java index 85f5295095..8f596882b0 100644 --- a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java +++ b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java @@ -20,13 +20,9 @@ import com.plotsquared.core.PlotSquared; import com.plotsquared.core.persistence.entity.PlotEntity; -import com.plotsquared.core.persistence.repository.api.PlotDeniedRepository; -import com.plotsquared.core.persistence.repository.api.PlotMembershipRepository; import com.plotsquared.core.persistence.repository.api.PlotRatingRepository; import com.plotsquared.core.persistence.repository.api.PlotRepository; -import com.plotsquared.core.persistence.repository.api.PlotTrustedRepository; import com.plotsquared.core.plot.Plot; -import com.plotsquared.core.plot.PlotId; import java.util.HashMap; import java.util.Optional; @@ -45,93 +41,6 @@ public class DBFunc { public static final UUID EVERYONE = UUID.fromString("1-1-3-3-7"); public static final UUID SERVER = UUID.fromString("00000000-0000-0000-0000-000000000000"); - /** - * @param plot - * @param uuid - */ - public static void removeTrusted(Plot plot, UUID uuid) { - if (plot == null) { - return; - } - PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - PlotTrustedRepository trustedRepo = PlotSquared.platform().injector().getInstance(PlotTrustedRepository.class); - String world = plot.getArea().toString(); - int x = plot.getId().getX(); - int z = plot.getId().getY(); - java.util.Optional ent = plotRepo.findByWorldAndId(world, x, z); - if (ent.isPresent() && ent.get().getId() != null) { - trustedRepo.remove(ent.get().getId(), uuid.toString()); - } - } - - /** - * @param plot - * @param uuid - */ - public static void removeMember(Plot plot, UUID uuid) { - PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - PlotMembershipRepository membershipRepo = PlotSquared.platform().injector().getInstance(PlotMembershipRepository.class); - String world = plot.getArea().toString(); - PlotId pid = plot.getId(); - Optional pe = plotRepo.findByWorldAndId(world, pid.getX(), pid.getY()); - pe.ifPresent(entity -> membershipRepo.remove(entity.getId(), uuid.toString())); - } - - /** - * @param plot - * @param uuid - */ - public static void setTrusted(Plot plot, UUID uuid) { - PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - PlotTrustedRepository trustedRepo = PlotSquared.platform().injector().getInstance(PlotTrustedRepository.class); - String world = plot.getArea().toString(); - PlotId pid = plot.getId(); - Optional pe = plotRepo.findByWorldAndId(world, pid.getX(), pid.getY()); - pe.ifPresent(entity -> trustedRepo.add(entity.getId(), uuid.toString())); - } - - /** - * @param plot - * @param uuid - */ - public static void setMember(Plot plot, UUID uuid) { - PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - PlotMembershipRepository membershipRepo = PlotSquared.platform().injector().getInstance(PlotMembershipRepository.class); - String world = plot.getArea().toString(); - PlotId pid = plot.getId(); - Optional pe = plotRepo.findByWorldAndId(world, pid.getX(), pid.getY()); - pe.ifPresent(entity -> membershipRepo.add(entity.getId(), uuid.toString())); - } - - /** - * @param plot - * @param uuid - */ - public static void removeDenied(Plot plot, UUID uuid) { - PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - PlotDeniedRepository deniedRepo = PlotSquared.platform().injector().getInstance(PlotDeniedRepository.class); - String world = plot.getArea().toString(); - PlotId pid = plot.getId(); - Optional pe = plotRepo.findByWorldAndId(world, pid.getX(), pid.getY()); - pe.ifPresent(entity -> deniedRepo.remove(entity.getId(), uuid.toString())); - } - - /** - * @param plot - * @param uuid - */ - public static void setDenied(Plot plot, UUID uuid) { - if (plot == null || uuid == null) { - return; - } - PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - PlotDeniedRepository deniedRepo = PlotSquared.platform().injector().getInstance(PlotDeniedRepository.class); - String world = plot.getArea().toString(); - PlotId pid = plot.getId(); - Optional pe = plotRepo.findByWorldAndId(world, pid.getX(), pid.getY()); - pe.ifPresent(entity -> deniedRepo.add(entity.getId(), uuid.toString())); - } - public static HashMap getRatings(Plot plot) { if (plot == null) { return new HashMap<>(0); diff --git a/Core/src/main/java/com/plotsquared/core/plot/Plot.java b/Core/src/main/java/com/plotsquared/core/plot/Plot.java index 72b892af12..7b8bd5284d 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/Plot.java +++ b/Core/src/main/java/com/plotsquared/core/plot/Plot.java @@ -54,6 +54,7 @@ import com.plotsquared.core.plot.world.SinglePlotArea; import com.plotsquared.core.queue.QueueCoordinator; import com.plotsquared.core.services.api.FlagService; +import com.plotsquared.core.services.api.MemberService; import com.plotsquared.core.services.api.PlotService; import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.MathMan; @@ -1074,7 +1075,7 @@ public void setMembers(final @NonNull Set uuids) { public void addDenied(final @NonNull UUID uuid) { for (final Plot current : getConnectedPlots()) { if (current.getDenied().add(uuid)) { - DBFunc.setDenied(current, uuid); + PlotSquared.platform().injector().getInstance(MemberService.class).setDenied(current, uuid); } } } @@ -1087,7 +1088,7 @@ public void addDenied(final @NonNull UUID uuid) { public void addTrusted(final @NonNull UUID uuid) { for (final Plot current : getConnectedPlots()) { if (current.getTrusted().add(uuid)) { - DBFunc.setTrusted(current, uuid); + PlotSquared.platform().injector().getInstance(MemberService.class).setTrusted(current, uuid); } } } @@ -1100,7 +1101,7 @@ public void addTrusted(final @NonNull UUID uuid) { public void addMember(final @NonNull UUID uuid) { for (final Plot current : getConnectedPlots()) { if (current.getMembers().add(uuid)) { - DBFunc.setMember(current, uuid); + PlotSquared.platform().injector().getInstance(MemberService.class).setMember(current, uuid); } } } @@ -2048,7 +2049,7 @@ public boolean removeDenied(UUID uuid) { private boolean rmvDenied(UUID uuid) { for (Plot current : this.getConnectedPlots()) { if (current.getDenied().remove(uuid)) { - DBFunc.removeDenied(current, uuid); + PlotSquared.platform().injector().getInstance(MemberService.class).removeDenied(current, uuid); } else { return false; } @@ -2077,7 +2078,7 @@ public boolean removeTrusted(UUID uuid) { private boolean rmvTrusted(UUID uuid) { for (Plot plot : this.getConnectedPlots()) { if (plot.getTrusted().remove(uuid)) { - DBFunc.removeTrusted(plot, uuid); + PlotSquared.platform().injector().getInstance(MemberService.class).removeTrusted(plot, uuid); } else { return false; } @@ -2109,7 +2110,7 @@ public boolean removeMember(UUID uuid) { private boolean rmvMember(UUID uuid) { for (Plot current : this.getConnectedPlots()) { if (current.getMembers().remove(uuid)) { - DBFunc.removeMember(current, uuid); + PlotSquared.platform().injector().getInstance(MemberService.class).removeMember(current, uuid); } else { return false; } diff --git a/Core/src/main/java/com/plotsquared/core/plot/PlotModificationManager.java b/Core/src/main/java/com/plotsquared/core/plot/PlotModificationManager.java index 102fa0aa7b..f917cb66f7 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/PlotModificationManager.java +++ b/Core/src/main/java/com/plotsquared/core/plot/PlotModificationManager.java @@ -25,7 +25,6 @@ import com.plotsquared.core.configuration.caption.Caption; import com.plotsquared.core.configuration.caption.LocaleHolder; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.events.PlotComponentSetEvent; import com.plotsquared.core.events.PlotMergeEvent; import com.plotsquared.core.events.PlotUnlinkEvent; @@ -39,6 +38,7 @@ import com.plotsquared.core.plot.flag.PlotFlag; import com.plotsquared.core.queue.QueueCoordinator; import com.plotsquared.core.services.api.FlagService; +import com.plotsquared.core.services.api.MemberService; import com.plotsquared.core.services.api.PlotService; import com.plotsquared.core.util.task.TaskManager; import com.plotsquared.core.util.task.TaskTime; @@ -138,19 +138,19 @@ public CompletableFuture copy(final @NonNull Plot destination, @Nullabl if (plot.members != null && !plot.members.isEmpty()) { other.members = plot.members; for (UUID member : plot.members) { - DBFunc.setMember(other, member); + PlotSquared.platform().injector().getInstance(MemberService.class).setMember(other, member); } } if (plot.trusted != null && !plot.trusted.isEmpty()) { other.trusted = plot.trusted; for (UUID trusted : plot.trusted) { - DBFunc.setTrusted(other, trusted); + PlotSquared.platform().injector().getInstance(MemberService.class).setTrusted(other, trusted); } } if (plot.denied != null && !plot.denied.isEmpty()) { other.denied = plot.denied; for (UUID denied : plot.denied) { - DBFunc.setDenied(other, denied); + PlotSquared.platform().injector().getInstance(MemberService.class).setDenied(other, denied); } } } diff --git a/Core/src/main/java/com/plotsquared/core/services/api/MemberService.java b/Core/src/main/java/com/plotsquared/core/services/api/MemberService.java new file mode 100644 index 0000000000..1ac0a1f582 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/api/MemberService.java @@ -0,0 +1,38 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.services.api; + +import com.plotsquared.core.plot.Plot; + +import java.util.UUID; + +public interface MemberService { + + void removeTrusted(Plot plot, UUID uuid); + + void removeMember(Plot plot, UUID uuid); + + void setTrusted(Plot plot, UUID uuid); + + void setMember(Plot plot, UUID uuid); + + void removeDenied(Plot plot, UUID uuid); + + void setDenied(Plot plot, UUID uuid); +} diff --git a/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java b/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java index d1b41243e3..81f3b3b456 100644 --- a/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java +++ b/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java @@ -22,11 +22,13 @@ import com.plotsquared.core.services.api.ClusterService; import com.plotsquared.core.services.api.CommentService; import com.plotsquared.core.services.api.FlagService; +import com.plotsquared.core.services.api.MemberService; import com.plotsquared.core.services.api.PlayerMetaService; import com.plotsquared.core.services.api.PlotService; import com.plotsquared.core.services.impl.ClusterDefaultService; import com.plotsquared.core.services.impl.CommentDefaultService; import com.plotsquared.core.services.impl.FlagDefaultService; +import com.plotsquared.core.services.impl.MemberDefaultService; import com.plotsquared.core.services.impl.PlayerMetaDefaultService; import com.plotsquared.core.services.impl.PlotDefaultService; @@ -39,6 +41,7 @@ protected void configure() { bind(ClusterService.class).to(ClusterDefaultService.class); bind(FlagService.class).to(FlagDefaultService.class); bind(CommentService.class).to(CommentDefaultService.class); + bind(MemberService.class).to(MemberDefaultService.class); } } diff --git a/Core/src/main/java/com/plotsquared/core/services/impl/MemberDefaultService.java b/Core/src/main/java/com/plotsquared/core/services/impl/MemberDefaultService.java new file mode 100644 index 0000000000..1ba9088d5d --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/impl/MemberDefaultService.java @@ -0,0 +1,136 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.services.impl; + +import com.plotsquared.core.persistence.entity.PlotEntity; +import com.plotsquared.core.persistence.repository.api.PlotDeniedRepository; +import com.plotsquared.core.persistence.repository.api.PlotMembershipRepository; +import com.plotsquared.core.persistence.repository.api.PlotRepository; +import com.plotsquared.core.persistence.repository.api.PlotTrustedRepository; +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.PlotId; +import com.plotsquared.core.services.api.MemberService; + +import java.util.Optional; +import java.util.UUID; + +public class MemberDefaultService implements MemberService { + + private final PlotRepository plotRepository; + private final PlotTrustedRepository trustedRepository; + private final PlotMembershipRepository membershipRepository; + private final PlotDeniedRepository deniedRepository; + + public MemberDefaultService(final PlotRepository repository, final PlotTrustedRepository trustedRepository, + final PlotMembershipRepository repo, final PlotDeniedRepository deniedRepository + ) { + this.plotRepository = repository; + this.trustedRepository = trustedRepository; + this.membershipRepository = repo; + this.deniedRepository = deniedRepository; + } + + @Override + public void removeTrusted(final Plot plot, final UUID uuid) { + String world = null; + if (plot.getArea() != null) { + world = plot.getArea().toString(); + } + if (world == null) { + return; + } + int x = plot.getId().getX(); + int z = plot.getId().getY(); + Optional ent = this.plotRepository.findByWorldAndId(world, x, z); + if (ent.isPresent() && ent.get().getId() != null) { + this.trustedRepository.remove(ent.get().getId(), uuid.toString()); + } + } + + @Override + public void removeMember(final Plot plot, final UUID uuid) { + String world = null; + if (plot.getArea() != null) { + world = plot.getArea().toString(); + } + if (world == null) { + return; + } + PlotId pid = plot.getId(); + Optional pe = this.plotRepository.findByWorldAndId(world, pid.getX(), pid.getY()); + pe.ifPresent(entity -> this.membershipRepository.remove(entity.getId(), uuid.toString())); + } + + @Override + public void setTrusted(final Plot plot, final UUID uuid) { + String world = null; + if (plot.getArea() != null) { + world = plot.getArea().toString(); + } + if (world == null) { + return; + } + PlotId pid = plot.getId(); + Optional pe = this.plotRepository.findByWorldAndId(world, pid.getX(), pid.getY()); + pe.ifPresent(entity -> this.trustedRepository.add(entity.getId(), uuid.toString())); + } + + @Override + public void setMember(final Plot plot, final UUID uuid) { + String world = null; + if (plot.getArea() != null) { + world = plot.getArea().toString(); + } + if (world == null) { + return; + } + PlotId pid = plot.getId(); + Optional pe = this.plotRepository.findByWorldAndId(world, pid.getX(), pid.getY()); + pe.ifPresent(entity -> membershipRepository.add(entity.getId(), uuid.toString())); + } + + @Override + public void removeDenied(final Plot plot, final UUID uuid) { + String world = null; + if (plot.getArea() != null) { + world = plot.getArea().toString(); + } + if (world == null) { + return; + } + PlotId pid = plot.getId(); + Optional pe = this.plotRepository.findByWorldAndId(world, pid.getX(), pid.getY()); + pe.ifPresent(entity -> this.deniedRepository.remove(entity.getId(), uuid.toString())); + } + + @Override + public void setDenied(final Plot plot, final UUID uuid) { + String world = null; + if (plot.getArea() != null) { + world = plot.getArea().toString(); + } + if (world == null) { + return; + } + PlotId pid = plot.getId(); + Optional pe = this.plotRepository.findByWorldAndId(world, pid.getX(), pid.getY()); + pe.ifPresent(entity -> this.deniedRepository.add(entity.getId(), uuid.toString())); + } + +} From 36a956c6b19ef84c8ba707acb0f8376ce6d98f00 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 01:54:37 +0200 Subject: [PATCH 139/141] feat: introduce RatingService and RatingDefaultService for plot rating management --- .../com/plotsquared/core/database/DBFunc.java | 73 ------------------- .../core/services/api/RatingService.java | 31 ++++++++ .../core/services/config/ServiceModule.java | 3 + .../services/impl/RatingDefaultService.java | 68 +++++++++++++++++ .../plotsquared/core/util/StaticUUIDs.java | 33 +++++++++ 5 files changed, 135 insertions(+), 73 deletions(-) delete mode 100644 Core/src/main/java/com/plotsquared/core/database/DBFunc.java create mode 100644 Core/src/main/java/com/plotsquared/core/services/api/RatingService.java create mode 100644 Core/src/main/java/com/plotsquared/core/services/impl/RatingDefaultService.java create mode 100644 Core/src/main/java/com/plotsquared/core/util/StaticUUIDs.java diff --git a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java deleted file mode 100644 index 8f596882b0..0000000000 --- a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.core.database; - -import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.persistence.entity.PlotEntity; -import com.plotsquared.core.persistence.repository.api.PlotRatingRepository; -import com.plotsquared.core.persistence.repository.api.PlotRepository; -import com.plotsquared.core.plot.Plot; - -import java.util.HashMap; -import java.util.Optional; -import java.util.UUID; - -/** - * Database Functions - * - These functions do not update the local plot objects and only make changes to the DB - */ -public class DBFunc { - - /** - * The "global" uuid. - */ - // TODO: Use this instead. public static final UUID EVERYONE = UUID.fromString("4aa2aaa4-c06b-485c-bc58-186aa1780d9b"); - public static final UUID EVERYONE = UUID.fromString("1-1-3-3-7"); - public static final UUID SERVER = UUID.fromString("00000000-0000-0000-0000-000000000000"); - - public static HashMap getRatings(Plot plot) { - if (plot == null) { - return new HashMap<>(0); - } - PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - PlotRatingRepository ratingRepo = PlotSquared.platform().injector().getInstance(PlotRatingRepository.class); - Optional pe = plotRepo.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); - HashMap out = new HashMap<>(); - pe.ifPresent(entity -> { - for (com.plotsquared.core.persistence.entity.PlotRatingEntity e : ratingRepo.findByPlotId(entity.getId())) { - try { - out.put(UUID.fromString(e.getPlayer()), e.getRating()); - } catch (IllegalArgumentException ignored) { - } - } - }); - return out; - } - - public static void setRating(Plot plot, UUID rater, int value) { - if (plot == null || rater == null) { - return; - } - PlotRepository plotRepo = PlotSquared.platform().injector().getInstance(PlotRepository.class); - PlotRatingRepository ratingRepo = PlotSquared.platform().injector().getInstance(PlotRatingRepository.class); - Optional pe = plotRepo.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); - pe.ifPresent(entity -> ratingRepo.upsert(entity.getId(), rater.toString(), value)); - } - -} diff --git a/Core/src/main/java/com/plotsquared/core/services/api/RatingService.java b/Core/src/main/java/com/plotsquared/core/services/api/RatingService.java new file mode 100644 index 0000000000..b15674bee7 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/api/RatingService.java @@ -0,0 +1,31 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.services.api; + +import com.plotsquared.core.plot.Plot; + +import java.util.HashMap; +import java.util.UUID; + +public interface RatingService { + + HashMap getRatings(Plot plot); + + void setRating(Plot plot, UUID rater, int value); +} diff --git a/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java b/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java index 81f3b3b456..18937ebfa0 100644 --- a/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java +++ b/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java @@ -25,12 +25,14 @@ import com.plotsquared.core.services.api.MemberService; import com.plotsquared.core.services.api.PlayerMetaService; import com.plotsquared.core.services.api.PlotService; +import com.plotsquared.core.services.api.RatingService; import com.plotsquared.core.services.impl.ClusterDefaultService; import com.plotsquared.core.services.impl.CommentDefaultService; import com.plotsquared.core.services.impl.FlagDefaultService; import com.plotsquared.core.services.impl.MemberDefaultService; import com.plotsquared.core.services.impl.PlayerMetaDefaultService; import com.plotsquared.core.services.impl.PlotDefaultService; +import com.plotsquared.core.services.impl.RatingDefaultService; public class ServiceModule extends AbstractModule { @@ -42,6 +44,7 @@ protected void configure() { bind(FlagService.class).to(FlagDefaultService.class); bind(CommentService.class).to(CommentDefaultService.class); bind(MemberService.class).to(MemberDefaultService.class); + bind(RatingService.class).to(RatingDefaultService.class); } } diff --git a/Core/src/main/java/com/plotsquared/core/services/impl/RatingDefaultService.java b/Core/src/main/java/com/plotsquared/core/services/impl/RatingDefaultService.java new file mode 100644 index 0000000000..5c1e8446e2 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/impl/RatingDefaultService.java @@ -0,0 +1,68 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.services.impl; + +import com.plotsquared.core.persistence.entity.PlotEntity; +import com.plotsquared.core.persistence.entity.PlotRatingEntity; +import com.plotsquared.core.persistence.repository.api.PlotRatingRepository; +import com.plotsquared.core.persistence.repository.api.PlotRepository; +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.services.api.RatingService; +import jakarta.inject.Inject; + +import java.util.HashMap; +import java.util.Optional; +import java.util.UUID; + +public class RatingDefaultService implements RatingService { + + private final PlotRepository plotRepository; + private final PlotRatingRepository ratingRepository; + + @Inject + public RatingDefaultService(final PlotRepository repository, final PlotRatingRepository ratingRepository) { + this.plotRepository = repository; + this.ratingRepository = ratingRepository; + } + + @Override + public HashMap getRatings(final Plot plot) { + if (plot.getWorldName() == null) { + return new HashMap<>(0); + } + Optional pe = this.plotRepository.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); + HashMap out = new HashMap<>(); + pe.ifPresent(entity -> { + for (PlotRatingEntity e : this.ratingRepository.findByPlotId(entity.getId())) { + out.put(UUID.fromString(e.getPlayer()), e.getRating()); + } + }); + return out; + } + + @Override + public void setRating(final Plot plot, final UUID rater, final int value) { + if (plot.getWorldName() == null) { + return; + } + Optional pe = this.plotRepository.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); + pe.ifPresent(entity -> this.ratingRepository.upsert(entity.getId(), rater.toString(), value)); + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/util/StaticUUIDs.java b/Core/src/main/java/com/plotsquared/core/util/StaticUUIDs.java new file mode 100644 index 0000000000..f8154e2940 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/util/StaticUUIDs.java @@ -0,0 +1,33 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.util; + + +import java.util.UUID; + +public class StaticUUIDs { + + /** + * The "global" uuid. + */ + // TODO: Use this instead. public static final UUID EVERYONE = UUID.fromString("4aa2aaa4-c06b-485c-bc58-186aa1780d9b"); + public static final UUID EVERYONE = UUID.fromString("1-1-3-3-7"); + public static final UUID SERVER = UUID.fromString("00000000-0000-0000-0000-000000000000"); + +} From 4097282d3d82a0a9a11e418f3905caeaabb411f4 Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 01:54:46 +0200 Subject: [PATCH 140/141] feat: replace DBFunc references with StaticUUIDs for improved clarity and consistency --- .../plotsquared/bukkit/BukkitPlatform.java | 4 ++-- .../listener/HighFreqBlockEventListener.java | 4 ++-- .../com/plotsquared/core/command/Add.java | 6 ++--- .../com/plotsquared/core/command/Deny.java | 8 +++---- .../com/plotsquared/core/command/Info.java | 6 ++--- .../com/plotsquared/core/command/Kick.java | 4 ++-- .../com/plotsquared/core/command/Like.java | 5 ++-- .../com/plotsquared/core/command/ListCmd.java | 6 ++--- .../com/plotsquared/core/command/Rate.java | 7 +++--- .../com/plotsquared/core/command/Remove.java | 4 ++-- .../com/plotsquared/core/command/Trust.java | 6 ++--- .../core/player/ConsolePlayer.java | 4 ++-- .../java/com/plotsquared/core/plot/Plot.java | 23 ++++++++++--------- .../plotsquared/core/plot/PlotCluster.java | 8 +++---- .../core/plot/expiration/ExpireManager.java | 4 ++-- .../plotsquared/core/util/PlayerManager.java | 19 ++++++++------- 16 files changed, 60 insertions(+), 58 deletions(-) diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java index c94925f26d..85517cad42 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java @@ -70,7 +70,7 @@ import com.plotsquared.core.configuration.Storage; import com.plotsquared.core.configuration.caption.ChatFormatter; import com.plotsquared.core.configuration.file.YamlConfiguration; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.util.StaticUUIDs; import com.plotsquared.core.events.RemoveRoadEntityEvent; import com.plotsquared.core.events.Result; import com.plotsquared.core.generator.GeneratorWrapper; @@ -490,7 +490,7 @@ public void onEnable() { this.backgroundPipeline.registerService(backgroundMojangService); } - this.impromptuPipeline.storeImmediately("*", DBFunc.EVERYONE); + this.impromptuPipeline.storeImmediately("*", StaticUUIDs.EVERYONE); if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) { injector.getInstance(PAPIPlaceholders.class).register(); diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/HighFreqBlockEventListener.java b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/HighFreqBlockEventListener.java index 24a01eb996..80bd2550bf 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/HighFreqBlockEventListener.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/HighFreqBlockEventListener.java @@ -23,7 +23,7 @@ import com.plotsquared.bukkit.util.BukkitUtil; import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Settings; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.util.StaticUUIDs; import com.plotsquared.core.location.Location; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; @@ -112,7 +112,7 @@ public void onRedstoneEvent(BlockRedstoneEvent event) { } if (Settings.Redstone.DISABLE_OFFLINE) { boolean disable = false; - if (!DBFunc.SERVER.equals(plot.getOwner())) { + if (!StaticUUIDs.SERVER.equals(plot.getOwner())) { if (plot.isMerged()) { disable = true; for (UUID owner : plot.getOwners()) { diff --git a/Core/src/main/java/com/plotsquared/core/command/Add.java b/Core/src/main/java/com/plotsquared/core/command/Add.java index 02a7124d24..715342f796 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Add.java +++ b/Core/src/main/java/com/plotsquared/core/command/Add.java @@ -22,7 +22,7 @@ import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.util.StaticUUIDs; import com.plotsquared.core.permissions.Permission; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; @@ -98,7 +98,7 @@ public CompletableFuture execute( int size = plot.getTrusted().size() + plot.getMembers().size(); while (iterator.hasNext()) { UUID uuid = iterator.next(); - if (uuid == DBFunc.EVERYONE && !(player.hasPermission(Permission.PERMISSION_TRUST_EVERYONE) || player.hasPermission( + if (uuid == StaticUUIDs.EVERYONE && !(player.hasPermission(Permission.PERMISSION_TRUST_EVERYONE) || player.hasPermission( Permission.PERMISSION_ADMIN_COMMAND_TRUST))) { player.sendMessage( TranslatableCaption.of("errors.invalid_player"), @@ -153,7 +153,7 @@ public CompletableFuture execute( // Success confirm.run(this, () -> { for (UUID uuid : uuids) { - if (uuid != DBFunc.EVERYONE) { + if (uuid != StaticUUIDs.EVERYONE) { if (!plot.removeTrusted(uuid)) { if (plot.getDenied().contains(uuid)) { plot.removeDenied(uuid); diff --git a/Core/src/main/java/com/plotsquared/core/command/Deny.java b/Core/src/main/java/com/plotsquared/core/command/Deny.java index 8d7365f6e0..290cae095a 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Deny.java +++ b/Core/src/main/java/com/plotsquared/core/command/Deny.java @@ -22,7 +22,7 @@ import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.util.StaticUUIDs; import com.plotsquared.core.events.TeleportCause; import com.plotsquared.core.location.Location; import com.plotsquared.core.permissions.Permission; @@ -104,7 +104,7 @@ public boolean onCommand(PlotPlayer player, String[] args) { ); } else { for (UUID uuid : uuids) { - if (uuid == DBFunc.EVERYONE && !( + if (uuid == StaticUUIDs.EVERYONE && !( player.hasPermission(Permission.PERMISSION_DENY_EVERYONE) || player.hasPermission(Permission.PERMISSION_ADMIN_COMMAND_DENY))) { player.sendMessage( TranslatableCaption.of("errors.invalid_player"), @@ -124,13 +124,13 @@ public boolean onCommand(PlotPlayer player, String[] args) { ); return; } else { - if (uuid != DBFunc.EVERYONE) { + if (uuid != StaticUUIDs.EVERYONE) { plot.removeMember(uuid); plot.removeTrusted(uuid); } plot.addDenied(uuid); this.eventDispatcher.callDenied(player, plot, uuid, true); - if (!uuid.equals(DBFunc.EVERYONE)) { + if (!uuid.equals(StaticUUIDs.EVERYONE)) { handleKick(PlotSquared.platform().playerManager().getPlayerIfExists(uuid), plot); } else { for (PlotPlayer plotPlayer : plot.getPlayersInPlot()) { diff --git a/Core/src/main/java/com/plotsquared/core/command/Info.java b/Core/src/main/java/com/plotsquared/core/command/Info.java index 3efabe114d..b9f1998160 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Info.java +++ b/Core/src/main/java/com/plotsquared/core/command/Info.java @@ -21,7 +21,7 @@ import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.caption.Caption; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.util.StaticUUIDs; import com.plotsquared.core.permissions.Permission; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; @@ -111,8 +111,8 @@ public boolean onCommand(final PlotPlayer player, String[] args) { boolean hasOwner = plot.hasOwner(); // Wildcard player {added} - boolean containsEveryone = plot.getTrusted().contains(DBFunc.EVERYONE); - boolean trustedEveryone = plot.getMembers().contains(DBFunc.EVERYONE); + boolean containsEveryone = plot.getTrusted().contains(StaticUUIDs.EVERYONE); + boolean trustedEveryone = plot.getMembers().contains(StaticUUIDs.EVERYONE); // Unclaimed? if (!hasOwner && !containsEveryone && !trustedEveryone) { player.sendMessage( diff --git a/Core/src/main/java/com/plotsquared/core/command/Kick.java b/Core/src/main/java/com/plotsquared/core/command/Kick.java index ced145fa58..16c32b6c8d 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Kick.java +++ b/Core/src/main/java/com/plotsquared/core/command/Kick.java @@ -21,7 +21,7 @@ import com.google.inject.Inject; import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.util.StaticUUIDs; import com.plotsquared.core.location.Location; import com.plotsquared.core.permissions.Permission; import com.plotsquared.core.player.PlotPlayer; @@ -86,7 +86,7 @@ public boolean onCommand(PlotPlayer player, String[] args) { } else { Set> players = new HashSet<>(); for (UUID uuid : uuids) { - if (uuid == DBFunc.EVERYONE) { + if (uuid == StaticUUIDs.EVERYONE) { for (PlotPlayer pp : plot.getPlayersInPlot()) { if (pp == player || pp.hasPermission(Permission.PERMISSION_ADMIN_ENTRY_DENIED)) { continue; diff --git a/Core/src/main/java/com/plotsquared/core/command/Like.java b/Core/src/main/java/com/plotsquared/core/command/Like.java index 78a60327dc..1f4c0369d6 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Like.java +++ b/Core/src/main/java/com/plotsquared/core/command/Like.java @@ -19,9 +19,9 @@ package com.plotsquared.core.command; import com.google.inject.Inject; +import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.events.PlotRateEvent; import com.plotsquared.core.events.TeleportCause; import com.plotsquared.core.permissions.Permission; @@ -29,6 +29,7 @@ import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.Rating; import com.plotsquared.core.plot.flag.implementations.DoneFlag; +import com.plotsquared.core.services.api.RatingService; import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.TabCompletions; import com.plotsquared.core.util.query.PlotQuery; @@ -184,7 +185,7 @@ protected boolean handleLike( if (plot.getSettings().getRatings() == null) { if (!Settings.Enabled_Components.RATING_CACHE) { TaskManager.runTaskAsync(() -> { - plot.getSettings().setRatings(DBFunc.getRatings(plot)); + plot.getSettings().setRatings(PlotSquared.platform().injector().getInstance(RatingService.class).getRatings(plot)); run.run(); }); return true; diff --git a/Core/src/main/java/com/plotsquared/core/command/ListCmd.java b/Core/src/main/java/com/plotsquared/core/command/ListCmd.java index 2766721ffd..38e6b7cca7 100644 --- a/Core/src/main/java/com/plotsquared/core/command/ListCmd.java +++ b/Core/src/main/java/com/plotsquared/core/command/ListCmd.java @@ -24,7 +24,7 @@ import com.plotsquared.core.configuration.caption.Caption; import com.plotsquared.core.configuration.caption.CaptionHolder; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.util.StaticUUIDs; import com.plotsquared.core.permissions.Permission; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; @@ -419,7 +419,7 @@ public void run(Integer i, Plot plot, CaptionHolder caption) { Caption color; if (plot.getOwner() == null) { color = TranslatableCaption.of("info.plot_list_no_owner"); - } else if (plot.isOwner(player.getUUID()) || plot.getOwner().equals(DBFunc.EVERYONE)) { + } else if (plot.isOwner(player.getUUID()) || plot.getOwner().equals(StaticUUIDs.EVERYONE)) { color = TranslatableCaption.of("info.plot_list_owned_by"); } else if (plot.isAdded(player.getUUID())) { color = TranslatableCaption.of("info.plot_list_added_to"); @@ -487,7 +487,7 @@ public void run(Integer i, Plot plot, CaptionHolder caption) { Tag.inserting(TranslatableCaption.of("info.unknown").toComponent(player)) ); builder.append(MINI_MESSAGE.deserialize(unknown, unknownResolver)); - } else if (uuidMapping.uuid().equals(DBFunc.EVERYONE)) { + } else if (uuidMapping.uuid().equals(StaticUUIDs.EVERYONE)) { TagResolver everyoneResolver = TagResolver.resolver( "everyone", Tag.inserting(TranslatableCaption.of("info.everyone").toComponent(player)) diff --git a/Core/src/main/java/com/plotsquared/core/command/Rate.java b/Core/src/main/java/com/plotsquared/core/command/Rate.java index 6e1319cc84..a2425a9d5f 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Rate.java +++ b/Core/src/main/java/com/plotsquared/core/command/Rate.java @@ -19,9 +19,9 @@ package com.plotsquared.core.command; import com.google.inject.Inject; +import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.events.PlotRateEvent; import com.plotsquared.core.events.TeleportCause; import com.plotsquared.core.permissions.Permission; @@ -31,6 +31,7 @@ import com.plotsquared.core.plot.PlotItemStack; import com.plotsquared.core.plot.Rating; import com.plotsquared.core.plot.flag.implementations.DoneFlag; +import com.plotsquared.core.services.api.RatingService; import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.InventoryUtil; import com.plotsquared.core.util.MathMan; @@ -210,7 +211,7 @@ public boolean onClick(int i) { if (plot.getSettings().getRatings() == null) { if (!Settings.Enabled_Components.RATING_CACHE) { TaskManager.runTaskAsync(() -> { - plot.getSettings().setRatings(DBFunc.getRatings(plot)); + plot.getSettings().setRatings(PlotSquared.platform().injector().getInstance(RatingService.class).getRatings(plot)); run.run(); }); return true; @@ -258,7 +259,7 @@ public boolean onClick(int i) { if (plot.getSettings().getRatings() == null) { if (!Settings.Enabled_Components.RATING_CACHE) { TaskManager.runTaskAsync(() -> { - plot.getSettings().setRatings(DBFunc.getRatings(plot)); + plot.getSettings().setRatings(PlotSquared.platform().injector().getInstance(RatingService.class).getRatings(plot)); run.run(); }); return true; diff --git a/Core/src/main/java/com/plotsquared/core/command/Remove.java b/Core/src/main/java/com/plotsquared/core/command/Remove.java index e2fd2faca5..4846c4bd9e 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Remove.java +++ b/Core/src/main/java/com/plotsquared/core/command/Remove.java @@ -20,7 +20,7 @@ import com.google.inject.Inject; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.util.StaticUUIDs; import com.plotsquared.core.permissions.Permission; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; @@ -97,7 +97,7 @@ public boolean onCommand(PlotPlayer player, String[] args) { this.eventDispatcher.callDenied(player, plot, uuid, false); count++; } - } else if (uuid == DBFunc.EVERYONE) { + } else if (uuid == StaticUUIDs.EVERYONE) { count += plot.getTrusted().size(); if (plot.removeTrusted(uuid)) { this.eventDispatcher.callTrusted(player, plot, uuid, false); diff --git a/Core/src/main/java/com/plotsquared/core/command/Trust.java b/Core/src/main/java/com/plotsquared/core/command/Trust.java index 23d306ad39..5526fae074 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Trust.java +++ b/Core/src/main/java/com/plotsquared/core/command/Trust.java @@ -22,7 +22,7 @@ import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.util.StaticUUIDs; import com.plotsquared.core.permissions.Permission; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; @@ -100,7 +100,7 @@ public CompletableFuture execute( int size = currentPlot.getTrusted().size() + currentPlot.getMembers().size(); while (iterator.hasNext()) { UUID uuid = iterator.next(); - if (uuid == DBFunc.EVERYONE && !( + if (uuid == StaticUUIDs.EVERYONE && !( player.hasPermission(Permission.PERMISSION_TRUST_EVERYONE) || player.hasPermission(Permission.PERMISSION_ADMIN_COMMAND_TRUST))) { player.sendMessage( TranslatableCaption.of("errors.invalid_player"), @@ -152,7 +152,7 @@ public CompletableFuture execute( // Success confirm.run(this, () -> { for (UUID uuid : uuids) { - if (uuid != DBFunc.EVERYONE) { + if (uuid != StaticUUIDs.EVERYONE) { if (!currentPlot.removeMember(uuid)) { if (currentPlot.getDenied().contains(uuid)) { currentPlot.removeDenied(uuid); diff --git a/Core/src/main/java/com/plotsquared/core/player/ConsolePlayer.java b/Core/src/main/java/com/plotsquared/core/player/ConsolePlayer.java index 87d3ff5798..931e7eb007 100644 --- a/Core/src/main/java/com/plotsquared/core/player/ConsolePlayer.java +++ b/Core/src/main/java/com/plotsquared/core/player/ConsolePlayer.java @@ -24,7 +24,7 @@ import com.plotsquared.core.configuration.caption.Caption; import com.plotsquared.core.configuration.caption.CaptionUtility; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.util.StaticUUIDs; import com.plotsquared.core.events.TeleportCause; import com.plotsquared.core.inject.annotations.ConsoleActor; import com.plotsquared.core.location.Location; @@ -128,7 +128,7 @@ public Location getLocationFull() { @NonNull @Override public UUID getUUID() { - return DBFunc.EVERYONE; + return StaticUUIDs.EVERYONE; } @Override diff --git a/Core/src/main/java/com/plotsquared/core/plot/Plot.java b/Core/src/main/java/com/plotsquared/core/plot/Plot.java index 7b8bd5284d..170f53c01a 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/Plot.java +++ b/Core/src/main/java/com/plotsquared/core/plot/Plot.java @@ -28,7 +28,7 @@ import com.plotsquared.core.configuration.caption.CaptionUtility; import com.plotsquared.core.configuration.caption.StaticCaption; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.util.StaticUUIDs; import com.plotsquared.core.events.PlayerTeleportToPlotEvent; import com.plotsquared.core.events.Result; import com.plotsquared.core.events.TeleportCause; @@ -56,6 +56,7 @@ import com.plotsquared.core.services.api.FlagService; import com.plotsquared.core.services.api.MemberService; import com.plotsquared.core.services.api.PlotService; +import com.plotsquared.core.services.api.RatingService; import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.MathMan; import com.plotsquared.core.util.PlayerManager; @@ -679,7 +680,7 @@ public boolean isOwnerAbs(final @Nullable UUID uuid) { */ public @Nullable UUID getOwner() { if (this.getFlag(ServerPlotFlag.class)) { - return DBFunc.SERVER; + return StaticUUIDs.SERVER; } return this.getOwnerAbs(); } @@ -746,10 +747,10 @@ public boolean isAdded(final @NonNull UUID uuid) { if (getMembers().contains(uuid)) { return isOnline(); } - if (getTrusted().contains(uuid) || getTrusted().contains(DBFunc.EVERYONE)) { + if (getTrusted().contains(uuid) || getTrusted().contains(StaticUUIDs.EVERYONE)) { return true; } - if (getMembers().contains(DBFunc.EVERYONE)) { + if (getMembers().contains(StaticUUIDs.EVERYONE)) { return isOnline(); } return false; @@ -762,7 +763,7 @@ public boolean isAdded(final @NonNull UUID uuid) { * @return {@code false} if the player is allowed to enter the plot, else {@code true} */ public boolean isDenied(final @NonNull UUID uuid) { - return this.denied != null && (this.denied.contains(DBFunc.EVERYONE) && !this.isAdded(uuid) || !this.isAdded(uuid) && this.denied + return this.denied != null && (this.denied.contains(StaticUUIDs.EVERYONE) && !this.isAdded(uuid) || !this.isAdded(uuid) && this.denied .contains(uuid)); } @@ -1713,7 +1714,7 @@ public boolean addRating(UUID uuid, Rating rating) { } int aggregate = rating.getAggregate(); baseSettings.getRatings().put(uuid, aggregate); - DBFunc.setRating(base, uuid, aggregate); + PlotSquared.platform().injector().getInstance(RatingService.class).setRating(base, uuid, aggregate); return true; } @@ -2036,7 +2037,7 @@ public String toString() { * @return success or not */ public boolean removeDenied(UUID uuid) { - if (uuid == DBFunc.EVERYONE && !denied.contains(uuid)) { + if (uuid == StaticUUIDs.EVERYONE && !denied.contains(uuid)) { boolean result = false; for (UUID other : new HashSet<>(getDenied())) { result = rmvDenied(other) || result; @@ -2065,7 +2066,7 @@ private boolean rmvDenied(UUID uuid) { * @return success or not */ public boolean removeTrusted(UUID uuid) { - if (uuid == DBFunc.EVERYONE && !trusted.contains(uuid)) { + if (uuid == StaticUUIDs.EVERYONE && !trusted.contains(uuid)) { boolean result = false; for (UUID other : new HashSet<>(getTrusted())) { result = rmvTrusted(other) || result; @@ -2097,7 +2098,7 @@ public boolean removeMember(UUID uuid) { if (this.members == null) { return false; } - if (uuid == DBFunc.EVERYONE && !members.contains(uuid)) { + if (uuid == StaticUUIDs.EVERYONE && !members.contains(uuid)) { boolean result = false; for (UUID other : new HashSet<>(this.members)) { result = rmvMember(other) || result; @@ -2929,7 +2930,7 @@ public CompletableFuture format(final Caption iInfo, PlotPlayer play Component owner; if (this.getOwner() == null) { owner = Component.text("unowned"); - } else if (this.getOwner().equals(DBFunc.SERVER)) { + } else if (this.getOwner().equals(StaticUUIDs.SERVER)) { owner = Component.text(MINI_MESSAGE.stripTags(TranslatableCaption .of("info.server") .getComponent(player))); @@ -3046,7 +3047,7 @@ public CompletableFuture format(final Caption iInfo, PlotPlayer play } else if (Settings.Enabled_Components.RATING_CACHE) { rating = new HashMap<>(); } else { - rating = DBFunc.getRatings(this); + rating = PlotSquared.platform().injector().getInstance(RatingService.class).getRatings(this); } int size = 1; if (!Settings.Ratings.CATEGORIES.isEmpty()) { diff --git a/Core/src/main/java/com/plotsquared/core/plot/PlotCluster.java b/Core/src/main/java/com/plotsquared/core/plot/PlotCluster.java index 3bb87fc3b6..221d15e26d 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/PlotCluster.java +++ b/Core/src/main/java/com/plotsquared/core/plot/PlotCluster.java @@ -19,7 +19,7 @@ package com.plotsquared.core.plot; import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.util.StaticUUIDs; import com.plotsquared.core.location.BlockLoc; import com.plotsquared.core.location.Location; import com.plotsquared.core.util.RegionUtil; @@ -103,13 +103,13 @@ public boolean isOwner(UUID uuid) { public boolean isAdded(UUID uuid) { return this.owner.equals(uuid) || this.invited.contains(uuid) || this.invited - .contains(DBFunc.EVERYONE) || this.helpers.contains(uuid) || this.helpers - .contains(DBFunc.EVERYONE); + .contains(StaticUUIDs.EVERYONE) || this.helpers.contains(uuid) || this.helpers + .contains(StaticUUIDs.EVERYONE); } public boolean hasHelperRights(UUID uuid) { return this.owner.equals(uuid) || this.helpers.contains(uuid) || this.helpers - .contains(DBFunc.EVERYONE); + .contains(StaticUUIDs.EVERYONE); } public String getName() { diff --git a/Core/src/main/java/com/plotsquared/core/plot/expiration/ExpireManager.java b/Core/src/main/java/com/plotsquared/core/plot/expiration/ExpireManager.java index 81b0555e1b..9605f992a3 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/expiration/ExpireManager.java +++ b/Core/src/main/java/com/plotsquared/core/plot/expiration/ExpireManager.java @@ -22,7 +22,7 @@ import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.caption.Caption; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.util.StaticUUIDs; import com.plotsquared.core.events.PlotFlagAddEvent; import com.plotsquared.core.events.PlotUnlinkEvent; import com.plotsquared.core.events.Result; @@ -467,7 +467,7 @@ public long getAge(UUID uuid, final boolean shouldDeleteUnknownOwner) { } public long getAge(Plot plot, final boolean shouldDeleteUnknownOwner) { - if (!plot.hasOwner() || Objects.equals(DBFunc.EVERYONE, plot.getOwner()) + if (!plot.hasOwner() || Objects.equals(StaticUUIDs.EVERYONE, plot.getOwner()) || PlotSquared.platform().playerManager().getPlayerIfExists(plot.getOwner()) != null || plot.getRunning() > 0) { return 0; } diff --git a/Core/src/main/java/com/plotsquared/core/util/PlayerManager.java b/Core/src/main/java/com/plotsquared/core/util/PlayerManager.java index 0d5f66e229..f2bfd41558 100644 --- a/Core/src/main/java/com/plotsquared/core/util/PlayerManager.java +++ b/Core/src/main/java/com/plotsquared/core/util/PlayerManager.java @@ -24,7 +24,6 @@ import com.plotsquared.core.configuration.caption.LocaleHolder; import com.plotsquared.core.configuration.caption.StaticCaption; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.player.ConsolePlayer; import com.plotsquared.core.player.OfflinePlotPlayer; import com.plotsquared.core.player.PlotPlayer; @@ -78,7 +77,7 @@ public static void getUUIDsFromString( consumer.accept(Collections.emptySet(), null); return; } else if ("*".equals(name)) { - result.add(DBFunc.EVERYONE); + result.add(StaticUUIDs.EVERYONE); } else if (name.length() > 16) { try { result.add(UUID.fromString(name)); @@ -127,9 +126,9 @@ public static void getUUIDsFromString( for (final UUID uuid : uuids) { if (uuid == null) { users.add(TranslatableCaption.of("info.none").toComponent(localeHolder)); - } else if (DBFunc.EVERYONE.equals(uuid)) { + } else if (StaticUUIDs.EVERYONE.equals(uuid)) { users.add(TranslatableCaption.of("info.everyone").toComponent(localeHolder)); - } else if (DBFunc.SERVER.equals(uuid)) { + } else if (StaticUUIDs.SERVER.equals(uuid)) { users.add(TranslatableCaption.of("info.console").toComponent(localeHolder)); } else { players.add(uuid); @@ -193,10 +192,10 @@ public static void getUUIDsFromString( if (owner == null) { return TranslatableCaption.of("info.none"); } - if (owner.equals(DBFunc.EVERYONE)) { + if (owner.equals(StaticUUIDs.EVERYONE)) { return TranslatableCaption.of("info.everyone"); } - if (owner.equals(DBFunc.SERVER)) { + if (owner.equals(StaticUUIDs.SERVER)) { return TranslatableCaption.of("info.server"); } final String name; @@ -226,8 +225,8 @@ public static void getUUIDsFromString( * Special Cases: *

    *
  • {@code null}: Resolves to a {@link TranslatableCaption} with the key {@code info.none}
  • - *
  • {@link DBFunc#EVERYONE}: Resolves to a {@link TranslatableCaption} with the key {@code info.everyone}
  • - *
  • {@link DBFunc#SERVER}: Resolves to a {@link TranslatableCaption} with the key {@code info.server}
  • + *
  • {@link StaticUUIDs#EVERYONE}: Resolves to a {@link TranslatableCaption} with the key {@code info.everyone}
  • + *
  • {@link StaticUUIDs#SERVER}: Resolves to a {@link TranslatableCaption} with the key {@code info.server}
  • *
*
* Otherwise, if the UUID is a valid UUID and not reserved by PlotSquared itself, this method first attempts to query the @@ -244,10 +243,10 @@ public static void getUUIDsFromString( if (uuid == null) { return CompletableFuture.completedFuture(TranslatableCaption.of("info.none")); } - if (uuid.equals(DBFunc.EVERYONE)) { + if (uuid.equals(StaticUUIDs.EVERYONE)) { return CompletableFuture.completedFuture(TranslatableCaption.of("info.everyone")); } - if (uuid.equals(DBFunc.SERVER)) { + if (uuid.equals(StaticUUIDs.SERVER)) { return CompletableFuture.completedFuture(TranslatableCaption.of("info.server")); } P player = getPlayerIfExists(uuid); From cb4fcbd0a988a5bdf4a6fb956a3dba04075d4e1c Mon Sep 17 00:00:00 2001 From: Phillipp Glanz Date: Sun, 7 Sep 2025 01:56:30 +0200 Subject: [PATCH 141/141] feat: add dependency injection for MemberDefaultService --- .../plotsquared/core/services/impl/MemberDefaultService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Core/src/main/java/com/plotsquared/core/services/impl/MemberDefaultService.java b/Core/src/main/java/com/plotsquared/core/services/impl/MemberDefaultService.java index 1ba9088d5d..1086db74f3 100644 --- a/Core/src/main/java/com/plotsquared/core/services/impl/MemberDefaultService.java +++ b/Core/src/main/java/com/plotsquared/core/services/impl/MemberDefaultService.java @@ -26,6 +26,7 @@ import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotId; import com.plotsquared.core.services.api.MemberService; +import jakarta.inject.Inject; import java.util.Optional; import java.util.UUID; @@ -37,6 +38,7 @@ public class MemberDefaultService implements MemberService { private final PlotMembershipRepository membershipRepository; private final PlotDeniedRepository deniedRepository; + @Inject public MemberDefaultService(final PlotRepository repository, final PlotTrustedRepository trustedRepository, final PlotMembershipRepository repo, final PlotDeniedRepository deniedRepository ) {