diff --git a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/mapper/flag/FlagContainerMappingStrategy.java b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/mapper/flag/FlagContainerMappingStrategy.java index 58816570..17118c26 100644 --- a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/mapper/flag/FlagContainerMappingStrategy.java +++ b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/mapper/flag/FlagContainerMappingStrategy.java @@ -19,6 +19,11 @@ import java.util.List; import java.util.function.Function; +/** + * Must be invoked while the Hibernate {@link org.hibernate.Session} that loaded the entity + * is still open — this strategy traverses {@code land}, {@code naturalFlags}, + * {@code roleFlags} and {@code entityCapFlags} lazy associations. + */ public final class FlagContainerMappingStrategy implements MapperStrategy { @Override @@ -27,25 +32,33 @@ public Function entityToModel() { if (entity == null) return null; if (!(entity instanceof FlagContainerDto flagContainer)) return null; - MappingContext mappingContext = MappingContext.create(); - mappingContext.setMappingStrategy(LandMappingStrategy.create()); - mappingContext.setMappingType(MapperType.ENTITY_TO_MODEL); - - Land land = (Land) mappingContext.doMapping(flagContainer.land()); + MappingContext landCtx = MappingContext.create(); + landCtx.setMappingStrategy(LandMappingStrategy.create()); + landCtx.setMappingType(MapperType.ENTITY_TO_MODEL); + Land land = (Land) landCtx.doMapping(flagContainer.land()); + MappingContext naturalCtx = MappingContext.create(); + naturalCtx.setMappingStrategy(NaturalFlagMappingStrategy.create()); + naturalCtx.setMappingType(MapperType.ENTITY_TO_MODEL); List naturalFlags = flagContainer.naturalFlags() .stream() - .map(naturalFlagDBO -> (LandNaturalFlag) mappingContext.doMapping(naturalFlagDBO)) + .map(flag -> (LandNaturalFlag) naturalCtx.doMapping(flag)) .toList(); + MappingContext roleCtx = MappingContext.create(); + roleCtx.setMappingStrategy(RoleFlagMappingStrategy.create()); + roleCtx.setMappingType(MapperType.ENTITY_TO_MODEL); List roleFlags = flagContainer.roleFlags() .stream() - .map(naturalFlagDBO -> (LandRoleFlag) mappingContext.doMapping(naturalFlagDBO)) + .map(flag -> (LandRoleFlag) roleCtx.doMapping(flag)) .toList(); + MappingContext capCtx = MappingContext.create(); + capCtx.setMappingStrategy(EntityCapFlagMappingStrategy.create()); + capCtx.setMappingType(MapperType.ENTITY_TO_MODEL); List entityCapFlags = flagContainer.entityCapFlags() .stream() - .map(naturalFlagDBO -> (LandEntityCapFlag) mappingContext.doMapping(naturalFlagDBO)) + .map(flag -> (LandEntityCapFlag) capCtx.doMapping(flag)) .toList(); return new FlagContainer(flagContainer.id(), land, naturalFlags, roleFlags, entityCapFlags); @@ -59,27 +72,35 @@ public Function modelToEntity() { if (model == null) return null; if(!(model instanceof FlagContainer flagContainer)) return null; - MappingContext mappingContext = MappingContext.create(); - mappingContext.setMappingStrategy(LandMappingStrategy.create()); - mappingContext.setMappingType(MapperType.MODEL_TO_ENTITY); + MappingContext landCtx = MappingContext.create(); + landCtx.setMappingStrategy(LandMappingStrategy.create()); + landCtx.setMappingType(MapperType.MODEL_TO_ENTITY); + LandEntity land = (LandEntity) landCtx.doMapping(flagContainer.getLand()); + MappingContext naturalCtx = MappingContext.create(); + naturalCtx.setMappingStrategy(NaturalFlagMappingStrategy.create()); + naturalCtx.setMappingType(MapperType.MODEL_TO_ENTITY); List naturalFlags = flagContainer.getNaturalFlags() .stream() - .map(naturalFlagDBO -> (LandNaturalFlagEntity) mappingContext.doMapping(naturalFlagDBO)) + .map(flag -> (LandNaturalFlagEntity) naturalCtx.doMapping(flag)) .toList(); + MappingContext roleCtx = MappingContext.create(); + roleCtx.setMappingStrategy(RoleFlagMappingStrategy.create()); + roleCtx.setMappingType(MapperType.MODEL_TO_ENTITY); List roleFlags = flagContainer.getRoleFlags() .stream() - .map(naturalFlagDBO -> (LandRoleFlagEntity) mappingContext.doMapping(naturalFlagDBO)) + .map(flag -> (LandRoleFlagEntity) roleCtx.doMapping(flag)) .toList(); + MappingContext capCtx = MappingContext.create(); + capCtx.setMappingStrategy(EntityCapFlagMappingStrategy.create()); + capCtx.setMappingType(MapperType.MODEL_TO_ENTITY); List entityCapFlags = flagContainer.getEntityCapFlags() .stream() - .map(naturalFlagDBO -> (LandEntityCapFlagEntity) mappingContext.doMapping(naturalFlagDBO)) + .map(flag -> (LandEntityCapFlagEntity) capCtx.doMapping(flag)) .toList(); - LandEntity land = (LandEntity) mappingContext.doMapping(flagContainer.getLand()); - return new FlagContainerEntity(flagContainer.getId(), land, naturalFlags, roleFlags, entityCapFlags); }; } diff --git a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/mapper/land/LandAreaMappingStrategy.java b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/mapper/land/LandAreaMappingStrategy.java index 8a280ac1..8a4c82ee 100644 --- a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/mapper/land/LandAreaMappingStrategy.java +++ b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/mapper/land/LandAreaMappingStrategy.java @@ -20,6 +20,10 @@ import java.util.List; import java.util.function.Function; +/** + * Must be invoked while the Hibernate {@link org.hibernate.Session} that loaded the entity + * is still open — this strategy traverses {@code members} and {@code chunks} lazy collections. + */ public final class LandAreaMappingStrategy implements MapperStrategy { public static LandAreaMappingStrategy create() { @@ -61,7 +65,7 @@ private Land getLand(LandDto land) { private List getChunks(List chunks) { MappingContext mappingContext = MappingContext.create(); - mappingContext.setMappingStrategy(create()); + mappingContext.setMappingStrategy(ClaimedChunkMappingStrategy.create()); mappingContext.setMappingType(MapperType.ENTITY_TO_MODEL); return chunks.stream().map(chunk -> (ClaimedChunk) mappingContext.doMapping(chunk)).toList(); } diff --git a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/mapper/land/LandMappingStrategy.java b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/mapper/land/LandMappingStrategy.java index efb313a8..768d1189 100644 --- a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/mapper/land/LandMappingStrategy.java +++ b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/mapper/land/LandMappingStrategy.java @@ -18,6 +18,11 @@ import java.util.List; import java.util.function.Function; +/** + * Must be invoked while the Hibernate {@link org.hibernate.Session} that loaded the entity + * is still open — this strategy traverses {@code owner}, {@code home}, {@code flagContainer}, + * and {@code areas}. Use {@code DatabaseLandService#getLands()} as the canonical JOIN FETCH pattern. + */ public final class LandMappingStrategy implements MapperStrategy { @Override diff --git a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/mapper/position/HomePositionMappingStrategy.java b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/mapper/position/HomePositionMappingStrategy.java index 1b5c9915..d2b9a6e3 100644 --- a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/mapper/position/HomePositionMappingStrategy.java +++ b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/mapper/position/HomePositionMappingStrategy.java @@ -14,7 +14,7 @@ public Function entityToModel() { return entity -> { if(entity == null) return null; if(!(entity instanceof HomePositionEntity home)) return null; - return new HomePositionEntity(home.id(), home.world(), home.posX(), home.posY(), home.posZ(), home.yaw(), home.pitch()); + return new HomePosition(home.id(), home.world(), home.posX(), home.posY(), home.posZ(), home.yaw(), home.pitch()); }; } diff --git a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/chunk/ClaimedChunkEntity.java b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/chunk/ClaimedChunkEntity.java index ac3792ad..56edc92e 100644 --- a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/chunk/ClaimedChunkEntity.java +++ b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/chunk/ClaimedChunkEntity.java @@ -5,19 +5,27 @@ import net.onelitefeather.pandorascluster.dto.chunk.ClaimedChunkDto; import net.onelitefeather.pandorascluster.dto.land.LandAreaDto; +import java.util.Objects; + @Entity -@Table(name = "land_chunks") +@Table( + name = "land_chunks", + uniqueConstraints = @UniqueConstraint( + name = "uk_land_chunks_area_chunk", + columnNames = {"landArea_id", "chunk_index"} + ) +) public final class ClaimedChunkEntity implements ClaimedChunkDto { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column + @Column(name = "chunk_index", nullable = false) private Long chunkIndex; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "landArea_id") + @JoinColumn(name = "landArea_id", nullable = false) private LandAreaEntity landArea; public ClaimedChunkEntity() { @@ -43,4 +51,17 @@ public Long chunkIndex() { public LandAreaDto landArea() { return landArea; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ClaimedChunkEntity that)) return false; + if (id == null || that.id == null) return false; + return Objects.equals(id, that.id); + } + + @Override + public int hashCode() { + return id == null ? System.identityHashCode(this) : Objects.hashCode(id); + } } diff --git a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/flag/FlagContainerEntity.java b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/flag/FlagContainerEntity.java index c08f9d71..930a1f98 100644 --- a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/flag/FlagContainerEntity.java +++ b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/flag/FlagContainerEntity.java @@ -10,6 +10,7 @@ import java.util.Collections; import java.util.List; +import java.util.Objects; @Entity @Table(name = "flag_containers") @@ -28,7 +29,7 @@ public final class FlagContainerEntity implements FlagContainerDto { @OneToMany(fetch = FetchType.LAZY, mappedBy = "flagContainer") private List entityCapFlags; - @OneToOne + @OneToOne(mappedBy = "flagContainerEntity") private LandEntity land; public static final FlagContainerEntity EMPTY = new FlagContainerEntity( @@ -83,4 +84,17 @@ public List roleFlags() { public LandDto land() { return this.land; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof FlagContainerEntity that)) return false; + if (id == null || that.id == null) return false; + return Objects.equals(id, that.id); + } + + @Override + public int hashCode() { + return id == null ? System.identityHashCode(this) : Objects.hashCode(id); + } } diff --git a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/flag/LandEntityCapFlagEntity.java b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/flag/LandEntityCapFlagEntity.java index 81d201d9..a3342f20 100644 --- a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/flag/LandEntityCapFlagEntity.java +++ b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/flag/LandEntityCapFlagEntity.java @@ -6,22 +6,30 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Objects; + @Entity -@Table(name = "entityCap_flags") +@Table( + name = "entityCap_flags", + uniqueConstraints = @UniqueConstraint( + name = "uk_entitycap_flags_container_name", + columnNames = {"flagContainer_id", "name"} + ) +) public final class LandEntityCapFlagEntity implements EntityCapFlagDto { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column + @Column(name = "name", length = 64, nullable = false) private String name; - @Column + @Column(name = "spawn_limit", nullable = false) private Integer spawnLimit; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "flagContainer_id") + @JoinColumn(name = "flagContainer_id", nullable = false) private FlagContainerEntity flagContainer; @@ -56,4 +64,17 @@ public Integer spawnLimit() { public FlagContainerDto flagContainer() { return this.flagContainer; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof LandEntityCapFlagEntity that)) return false; + if (id == null || that.id == null) return false; + return Objects.equals(id, that.id); + } + + @Override + public int hashCode() { + return id == null ? System.identityHashCode(this) : Objects.hashCode(id); + } } diff --git a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/flag/LandNaturalFlagEntity.java b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/flag/LandNaturalFlagEntity.java index 1f0be32f..04a4b18d 100644 --- a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/flag/LandNaturalFlagEntity.java +++ b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/flag/LandNaturalFlagEntity.java @@ -6,22 +6,30 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Objects; + @Entity -@Table(name = "natural_flags") +@Table( + name = "natural_flags", + uniqueConstraints = @UniqueConstraint( + name = "uk_natural_flags_container_name", + columnNames = {"flagContainer_id", "name"} + ) +) public final class LandNaturalFlagEntity implements NaturalFlagDto { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column + @Column(name = "name", length = 64, nullable = false) private String name; - @Column + @Column(name = "state", nullable = false) private boolean state; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "flagContainer_id") + @JoinColumn(name = "flagContainer_id", nullable = false) private FlagContainerEntity flagContainer; public LandNaturalFlagEntity() { @@ -54,4 +62,17 @@ public boolean state() { public FlagContainerDto flagContainer() { return flagContainer; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof LandNaturalFlagEntity that)) return false; + if (id == null || that.id == null) return false; + return Objects.equals(id, that.id); + } + + @Override + public int hashCode() { + return id == null ? System.identityHashCode(this) : Objects.hashCode(id); + } } diff --git a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/flag/LandRoleFlagEntity.java b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/flag/LandRoleFlagEntity.java index f42af5cb..3dcef477 100644 --- a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/flag/LandRoleFlagEntity.java +++ b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/flag/LandRoleFlagEntity.java @@ -7,25 +7,34 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Objects; + @Entity -@Table(name = "role_flags") +@Table( + name = "role_flags", + uniqueConstraints = @UniqueConstraint( + name = "uk_role_flags_container_name", + columnNames = {"flagContainer_id", "name"} + ) +) public final class LandRoleFlagEntity implements RoleFlagDto { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column + @Column(name = "name", length = 64, nullable = false) private String name; - @Column + @Column(name = "state", nullable = false) private boolean state; @Enumerated(EnumType.STRING) + @Column(name = "role", length = 32, nullable = false) private LandRole role; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "flagContainer_id") + @JoinColumn(name = "flagContainer_id", nullable = false) private FlagContainerEntity flagContainer; public LandRoleFlagEntity() { @@ -65,4 +74,16 @@ public FlagContainerDto flagContainer() { return this.flagContainer; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof LandRoleFlagEntity that)) return false; + if (id == null || that.id == null) return false; + return Objects.equals(id, that.id); + } + + @Override + public int hashCode() { + return id == null ? System.identityHashCode(this) : Objects.hashCode(id); + } } diff --git a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/land/LandAreaEntity.java b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/land/LandAreaEntity.java index 753f1ce0..6f23b75e 100644 --- a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/land/LandAreaEntity.java +++ b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/land/LandAreaEntity.java @@ -12,6 +12,7 @@ import java.util.Collections; import java.util.List; +import java.util.Objects; @Entity @Table(name = "land_areas") @@ -21,6 +22,7 @@ public final class LandAreaEntity implements LandAreaDto { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @Column(name = "name", length = 64, nullable = false) private String name; @OneToMany(fetch = FetchType.LAZY, mappedBy = "landArea") @@ -73,4 +75,17 @@ public LandAreaEntity(Long id, public LandDto land() { return this.land; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof LandAreaEntity that)) return false; + if (id == null || that.id == null) return false; + return Objects.equals(id, that.id); + } + + @Override + public int hashCode() { + return id == null ? System.identityHashCode(this) : Objects.hashCode(id); + } } diff --git a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/land/LandEntity.java b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/land/LandEntity.java index 2c6e8e7e..a6896f02 100644 --- a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/land/LandEntity.java +++ b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/land/LandEntity.java @@ -14,6 +14,7 @@ import java.util.Collections; import java.util.List; +import java.util.Objects; @Entity @Table(name = "lands") @@ -24,15 +25,18 @@ public final class LandEntity implements LandDto { private Long id; @ManyToOne + @JoinColumn(name = "owner_id", nullable = false) private LandPlayerEntity owner; @ManyToOne + @JoinColumn(name = "home_id", nullable = false) private HomePositionEntity home; @OneToMany(fetch = FetchType.LAZY, mappedBy = "land") private List areas; @OneToOne + @JoinColumn(name = "flag_container_id", nullable = false) private FlagContainerEntity flagContainerEntity; public LandEntity() { @@ -75,4 +79,17 @@ public LandEntity(Long id, public FlagContainerDto flagContainer() { return this.flagContainerEntity; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof LandEntity that)) return false; + if (id == null || that.id == null) return false; + return Objects.equals(id, that.id); + } + + @Override + public int hashCode() { + return id == null ? System.identityHashCode(this) : Objects.hashCode(id); + } } diff --git a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/player/LandMemberEntity.java b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/player/LandMemberEntity.java index c6465d65..a361e467 100644 --- a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/player/LandMemberEntity.java +++ b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/player/LandMemberEntity.java @@ -19,7 +19,8 @@ public final class LandMemberEntity implements LandMemberDto { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @OneToOne + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id", nullable = false) private LandPlayerEntity member; @Enumerated(EnumType.STRING) diff --git a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/player/LandPlayerEntity.java b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/player/LandPlayerEntity.java index 814c3bbb..dfddc020 100644 --- a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/player/LandPlayerEntity.java +++ b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/player/LandPlayerEntity.java @@ -15,10 +15,10 @@ public final class LandPlayerEntity implements LandPlayerDto { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(columnDefinition = "VARCHAR(36)") + @Column(name = "uuid", length = 36, nullable = false, unique = true) private String uuid; - @Column(columnDefinition = "VARCHAR(16)") + @Column(name = "name", length = 16, nullable = false) private String name; public LandPlayerEntity() { diff --git a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/position/HomePositionEntity.java b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/position/HomePositionEntity.java index 988beea4..116a1c37 100644 --- a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/position/HomePositionEntity.java +++ b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/models/position/HomePositionEntity.java @@ -15,22 +15,22 @@ public final class HomePositionEntity implements HomePositionDto { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column + @Column(name = "world", length = 64, nullable = false) private String world; - @Column + @Column(name = "pos_x", nullable = false) private Double posX; - @Column + @Column(name = "pos_y", nullable = false) private Double posY; - @Column + @Column(name = "pos_z", nullable = false) private Double posZ; - @Column + @Column(name = "yaw", nullable = false) private Float yaw; - @Column + @Column(name = "pitch", nullable = false) private Float pitch; public HomePositionEntity() { diff --git a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/service/DatabaseLandAreaService.java b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/service/DatabaseLandAreaService.java index ef81d370..c5e0add7 100644 --- a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/service/DatabaseLandAreaService.java +++ b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/service/DatabaseLandAreaService.java @@ -12,6 +12,7 @@ import net.onelitefeather.pandorascluster.database.mapper.land.LandAreaMappingStrategy; import net.onelitefeather.pandorascluster.database.models.chunk.ClaimedChunkEntity; import net.onelitefeather.pandorascluster.database.models.land.LandAreaEntity; +import org.hibernate.Hibernate; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.Transaction; @@ -60,13 +61,13 @@ public boolean removeClaimedChunk(long chunkIndex) { transaction = session.beginTransaction(); session.remove(toEntity(claimedChunk)); transaction.commit(); + return true; } catch (HibernateException e) { if (transaction != null) transaction.rollback(); Constants.LOGGER.log(Level.SEVERE, "Cannot delete claimed chunk", e); + return false; } - - return false; } @Override @@ -74,6 +75,7 @@ public boolean removeClaimedChunk(long chunkIndex) { try (Session session = this.databaseService.sessionFactory().openSession()) { var query = session.createQuery("SELECT cc FROM ClaimedChunkEntity cc WHERE cc.chunkIndex = :chunkIndex", ClaimedChunkEntity.class); + query.setParameter("chunkIndex", chunkIndex); return toModel(query.uniqueResult()); } catch (HibernateException e) { Constants.LOGGER.log(Level.SEVERE, "Could not find any chunk with chunkIndex %s".formatted(chunkIndex), e); @@ -85,13 +87,25 @@ public boolean removeClaimedChunk(long chunkIndex) { public @Nullable LandArea getLandArea(long chunkIndex) { try (Session session = this.databaseService.sessionFactory().openSession()) { - var query = session.createQuery("SELECT cc FROM ClaimedChunkEntity cc JOIN FETCH cc.landArea WHERE cc.chunkIndex = :chunkindex", ClaimedChunkEntity.class); - query.setParameter("chunkindex", chunkIndex); + var chunkQuery = session.createQuery( + "SELECT cc FROM ClaimedChunkEntity cc " + + "JOIN FETCH cc.landArea la " + + "LEFT JOIN FETCH la.land " + + "WHERE cc.chunkIndex = :chunkindex", + ClaimedChunkEntity.class); + chunkQuery.setParameter("chunkindex", chunkIndex); - ClaimedChunkEntity claimedChunk = query.uniqueResult(); + ClaimedChunkEntity claimedChunk = chunkQuery.uniqueResult(); if (claimedChunk == null) return null; LandAreaEntity landArea = (LandAreaEntity) claimedChunk.landArea(); + + // Hibernate forbids JOIN FETCH-ing two bag-style collections in one query + // (MultipleBagFetchException), so the members and chunks collections are + // initialized in separate round-trips. + Hibernate.initialize(landArea.members()); + Hibernate.initialize(landArea.chunks()); + return toModel(landArea); } catch (HibernateException e) { @@ -100,6 +114,12 @@ public boolean removeClaimedChunk(long chunkIndex) { } } + /** + * Best-effort composition of already-transactional sub-operations. Each call + * to {@code removeLandMember} and {@code removeClaimedChunk} opens its own + * Hibernate session and commits independently, so a partial failure leaves + * the area in an intermediate state. Do not rely on atomicity here. + */ @Override public void unclaimArea(LandArea landArea) { landArea.getMembers().forEach(this.pandorasCluster.getLandPlayerService()::removeLandMember); diff --git a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/service/DatabaseLandService.java b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/service/DatabaseLandService.java index 33353abf..16fb0359 100644 --- a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/service/DatabaseLandService.java +++ b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/service/DatabaseLandService.java @@ -47,7 +47,13 @@ public DatabaseLandService(PandorasCluster cluster) { @Override public @NotNull List getLands() { try (Session session = this.databaseService.sessionFactory().openSession()) { - var query = session.createQuery("SELECT l FROM LandEntity l", LandEntity.class); + var query = session.createQuery( + "SELECT DISTINCT l FROM LandEntity l " + + "LEFT JOIN FETCH l.owner " + + "LEFT JOIN FETCH l.home " + + "LEFT JOIN FETCH l.flagContainerEntity " + + "LEFT JOIN FETCH l.areas", + LandEntity.class); var lands = query.list(); return lands.stream().map(this::toModel).toList(); } catch (HibernateException e) { @@ -120,23 +126,28 @@ public void addLandArea(Land land, String name, List chunks) { try (Session session = this.databaseService.sessionFactory().openSession()) { transaction = session.beginTransaction(); + // Persist in FK-dependency order: home and flag container first (no outgoing + // non-null FKs), then the land (needs owner, home, flag_container), then the + // area and its first chunk. + var homeEntity = toHomePositionEntity(home); + session.persist(homeEntity); + var flagContainerEntity = new FlagContainerEntity(null, null, Collections.emptyList(), Collections.emptyList(), Collections.emptyList()); - var landEntity = new LandEntity(null, - new LandPlayerEntity(owner.getId(), owner.getUniqueId().toString(), owner.getName()), - toHomePositionEntity(home), - Collections.emptyList(), - flagContainerEntity); + session.persist(flagContainerEntity); - session.persist(flagContainerEntity.withLand(landEntity)); + var ownerRef = session.getReference(LandPlayerEntity.class, owner.getId()); + var landEntity = new LandEntity(null, ownerRef, homeEntity, Collections.emptyList(), flagContainerEntity); session.persist(landEntity); - session.persist(landEntity.home()); - transaction.commit(); - var land = new Land(landEntity.id(), owner, home, Collections.emptyList(), FlagContainer.EMPTY); + var landAreaEntity = new LandAreaEntity(null, "default", Collections.emptyList(), Collections.emptyList(), landEntity); + session.persist(landAreaEntity); - addLandArea(land, "default", List.of(chunk)); + var claimedChunkEntity = new ClaimedChunkEntity(null, chunk.getChunkIndex(), landAreaEntity); + session.persist(claimedChunkEntity); - return land; + transaction.commit(); + + return new Land(landEntity.id(), owner, home, Collections.emptyList(), FlagContainer.EMPTY); } catch (HibernateException e) { Constants.LOGGER.log(Level.SEVERE, "Cannot create land!", e); if (transaction != null) transaction.rollback(); @@ -147,19 +158,23 @@ public void addLandArea(Land land, String name, List chunks) { @Override public void unclaimLand(@NotNull Land land) { + removeFlagsFromLand(land); + land.getAreas().forEach(this.landAreaService::unclaimArea); Transaction transaction = null; try (Session session = this.databaseService.sessionFactory().openSession()) { transaction = session.beginTransaction(); - removeFlagsFromLand(land); - land.getAreas().forEach(this.landAreaService::unclaimArea); - - session.remove(land); - session.remove(toEntity(land.getHome())); + LandEntity landEntity = session.byId(LandEntity.class).load(land.getId()); + if (landEntity != null) { + HomePositionEntity homeEntity = (HomePositionEntity) landEntity.home(); + session.remove(landEntity); + if (homeEntity != null) session.remove(homeEntity); + } transaction.commit(); } catch (HibernateException e) { if (transaction != null) transaction.rollback(); + Constants.LOGGER.log(Level.SEVERE, "Cannot unclaim land.", e); } } diff --git a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/service/flag/DatabaseLandFlagService.java b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/service/flag/DatabaseLandFlagService.java index 3debf7e1..24fccd80 100644 --- a/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/service/flag/DatabaseLandFlagService.java +++ b/adapters/database/src/main/java/net/onelitefeather/pandorascluster/database/service/flag/DatabaseLandFlagService.java @@ -20,7 +20,6 @@ import net.onelitefeather.pandorascluster.database.models.flag.LandRoleFlagEntity; import org.hibernate.HibernateException; import org.hibernate.Session; -import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.jetbrains.annotations.NotNull; @@ -40,8 +39,7 @@ public DatabaseLandFlagService(PandorasCluster pandorasCluster) { public void addRoleFlag(@NotNull RoleFlag roleFlag, FlagContainer flagContainer) { Transaction transaction = null; - try (SessionFactory factory = this.databaseService.sessionFactory(); - Session session = factory.openSession()) { + try (Session session = this.databaseService.sessionFactory().openSession()) { transaction = session.beginTransaction(); @@ -58,8 +56,7 @@ public void addRoleFlag(@NotNull RoleFlag roleFlag, FlagContainer flagContainer) @Override public void updateRoleFlag(@NotNull LandRoleFlag roleFlag) { Transaction transaction = null; - try (SessionFactory factory = this.databaseService.sessionFactory(); - Session session = factory.openSession()) { + try (Session session = this.databaseService.sessionFactory().openSession()) { transaction = session.beginTransaction(); session.merge(getRoleFlagEntity(roleFlag)); @@ -74,8 +71,7 @@ public void updateRoleFlag(@NotNull LandRoleFlag roleFlag) { @Override public void removeRoleFlag(@NotNull LandRoleFlag roleFlag, @NotNull FlagContainer flagContainer) { Transaction transaction = null; - try (SessionFactory factory = this.databaseService.sessionFactory(); - Session session = factory.openSession()) { + try (Session session = this.databaseService.sessionFactory().openSession()) { transaction = session.beginTransaction(); @@ -93,8 +89,7 @@ public void removeRoleFlag(@NotNull LandRoleFlag roleFlag, @NotNull FlagContaine public void addNaturalFlag(@NotNull NaturalFlag naturalFlag, FlagContainer flagContainer) { Transaction transaction = null; - try (SessionFactory factory = this.databaseService.sessionFactory(); - Session session = factory.openSession()) { + try (Session session = this.databaseService.sessionFactory().openSession()) { transaction = session.beginTransaction(); @@ -111,8 +106,7 @@ public void addNaturalFlag(@NotNull NaturalFlag naturalFlag, FlagContainer flagC @Override public void updateNaturalCapFlag(@NotNull LandNaturalFlag naturalFlag) { Transaction transaction = null; - try (SessionFactory factory = this.databaseService.sessionFactory(); - Session session = factory.openSession()) { + try (Session session = this.databaseService.sessionFactory().openSession()) { transaction = session.beginTransaction(); session.merge(getNaturalFlagEntity(naturalFlag)); @@ -127,8 +121,7 @@ public void updateNaturalCapFlag(@NotNull LandNaturalFlag naturalFlag) { @Override public void removeNaturalFlag(@NotNull LandNaturalFlag naturalFlag, @NotNull FlagContainer flagContainer) { Transaction transaction = null; - try (SessionFactory factory = this.databaseService.sessionFactory(); - Session session = factory.openSession()) { + try (Session session = this.databaseService.sessionFactory().openSession()) { transaction = session.beginTransaction(); flagContainer.removeNaturalFlag(naturalFlag); @@ -145,8 +138,7 @@ public void removeNaturalFlag(@NotNull LandNaturalFlag naturalFlag, @NotNull Fla public void addEntityCapFlag(@NotNull EntityCapFlag entityCapFlag, FlagContainer flagContainer) { Transaction transaction = null; - try (SessionFactory factory = this.databaseService.sessionFactory(); - Session session = factory.openSession()) { + try (Session session = this.databaseService.sessionFactory().openSession()) { transaction = session.beginTransaction(); @@ -163,8 +155,7 @@ public void addEntityCapFlag(@NotNull EntityCapFlag entityCapFlag, FlagContainer @Override public void updateEntityCapFlag(@NotNull LandEntityCapFlag entityCapFlag) { Transaction transaction = null; - try (SessionFactory factory = this.databaseService.sessionFactory(); - Session session = factory.openSession()) { + try (Session session = this.databaseService.sessionFactory().openSession()) { transaction = session.beginTransaction(); session.merge(getEntityCapFlagEntity(entityCapFlag)); @@ -179,8 +170,7 @@ public void updateEntityCapFlag(@NotNull LandEntityCapFlag entityCapFlag) { @Override public void removeEntityCapFlag(@NotNull LandEntityCapFlag entityCapFlag, @NotNull FlagContainer flagContainer) { Transaction transaction = null; - try (SessionFactory factory = this.databaseService.sessionFactory(); - Session session = factory.openSession()) { + try (Session session = this.databaseService.sessionFactory().openSession()) { transaction = session.beginTransaction(); flagContainer.removeEntityCapFlag(entityCapFlag); diff --git a/common/build.gradle.kts b/common/build.gradle.kts index cc160537..43af5893 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -20,6 +20,7 @@ dependencies { testImplementation(project(":adapters:database")) testImplementation(project(":api")) + testImplementation(libs.h2) testImplementation(platform(libs.junitBom)) testImplementation(libs.junitApi) diff --git a/common/src/main/java/net/onelitefeather/pandorascluster/api/PandorasClusterImpl.java b/common/src/main/java/net/onelitefeather/pandorascluster/api/PandorasClusterImpl.java index 90d3ecfc..2b5379cb 100644 --- a/common/src/main/java/net/onelitefeather/pandorascluster/api/PandorasClusterImpl.java +++ b/common/src/main/java/net/onelitefeather/pandorascluster/api/PandorasClusterImpl.java @@ -1,14 +1,11 @@ package net.onelitefeather.pandorascluster.api; import net.onelitefeather.pandorascluster.api.service.*; -import net.onelitefeather.pandorascluster.api.util.Constants; import net.onelitefeather.pandorascluster.database.service.*; import net.onelitefeather.pandorascluster.database.service.flag.DatabaseLandFlagService; import org.hibernate.HibernateException; import org.hibernate.cfg.Configuration; -import java.util.logging.Level; - public class PandorasClusterImpl implements PandorasCluster, ThreadHelper { private DatabaseService databaseService; @@ -25,12 +22,10 @@ public PandorasClusterImpl() { var sessionFactory = new Configuration().configure().configure("connection.cfg.xml").buildSessionFactory(); this.databaseService = new DatabaseServiceImpl(sessionFactory); } catch (HibernateException e) { - this.databaseService = null; - Constants.LOGGER.log(Level.SEVERE, "Cannot build session factory.", e); + throw new IllegalStateException("Failed to build Hibernate SessionFactory — plugin cannot start", e); } }); - if (databaseService == null) return; this.landPlayerService = new DatabaseLandPlayerService(databaseService); this.landFlagService = new DatabaseLandFlagService(this); this.landAreaService = new DatabaseLandAreaService(this, databaseService); diff --git a/common/src/main/resources/hibernate.cfg.xml b/common/src/main/resources/hibernate.cfg.xml index 57929a0b..f69747d9 100644 --- a/common/src/main/resources/hibernate.cfg.xml +++ b/common/src/main/resources/hibernate.cfg.xml @@ -23,6 +23,16 @@ org.hibernate.cache.internal.NoCacheProvider - + + + + + + + + + + + - \ No newline at end of file + diff --git a/common/src/test/kotlin/net/onelitefeather/pandorascluster/api/TestDatabaseServiceImpl.kt b/common/src/test/kotlin/net/onelitefeather/pandorascluster/api/TestDatabaseServiceImpl.kt deleted file mode 100644 index 12fffee7..00000000 --- a/common/src/test/kotlin/net/onelitefeather/pandorascluster/api/TestDatabaseServiceImpl.kt +++ /dev/null @@ -1,56 +0,0 @@ -package net.onelitefeather.pandorascluster.api - -import net.onelitefeather.pandorascluster.api.chunk.ClaimedChunk -import net.onelitefeather.pandorascluster.api.land.Land -import net.onelitefeather.pandorascluster.api.land.flag.FlagRoleAttachment -import net.onelitefeather.pandorascluster.api.mapper.DatabaseEntityMapper -import net.onelitefeather.pandorascluster.api.player.LandMember -import net.onelitefeather.pandorascluster.api.player.LandPlayer -import net.onelitefeather.pandorascluster.api.position.HomePosition -import net.onelitefeather.pandorascluster.api.service.DatabaseService -import net.onelitefeather.pandorascluster.api.utils.ThreadHelper -import net.onelitefeather.pandorascluster.database.mapper.impl.* -import net.onelitefeather.pandorascluster.dbo.chunk.ClaimedChunkDBO -import net.onelitefeather.pandorascluster.dbo.flag.FlagRoleAttachmentDBO -import net.onelitefeather.pandorascluster.dbo.land.LandDBO -import net.onelitefeather.pandorascluster.dbo.player.LandMemberDBO -import net.onelitefeather.pandorascluster.dbo.player.LandPlayerDBO -import net.onelitefeather.pandorascluster.dbo.position.HomePositionDBO -import org.hibernate.HibernateException -import org.hibernate.SessionFactory -import org.hibernate.cfg.Configuration - -class TestDatabaseServiceImpl : DatabaseService, ThreadHelper { - - lateinit var sessionFactory: SessionFactory - - override fun connect(configFileResource: String) { - syncThreadForServiceLoader { - try { - sessionFactory = Configuration().configure().configure(configFileResource).buildSessionFactory() - } catch (e: HibernateException) { - throw HibernateException("Cannot build session factorty.", e) - } - } - } - - override fun shutdown() { - sessionFactory.close() - } - - override fun isRunning(): Boolean = sessionFactory.isOpen - - override fun sessionFactory(): SessionFactory = sessionFactory - - override fun landMapper(): DatabaseEntityMapper = LandEntityMapper(this) - - override fun landMemberMapper(): DatabaseEntityMapper = LandMemberMapper(this) - - override fun landPlayerMapper(): DatabaseEntityMapper = LandPlayerMapper() - - override fun claimedChunkMapper(): DatabaseEntityMapper = ClaimedChunkMapper() - - override fun homePositionMapper(): DatabaseEntityMapper = HomePositionMapper() - - override fun flagMapper(): DatabaseEntityMapper = FlagRoleAttachmentMapper() -} \ No newline at end of file diff --git a/common/src/test/kotlin/net/onelitefeather/pandorascluster/api/TestLandFlagService.kt b/common/src/test/kotlin/net/onelitefeather/pandorascluster/api/TestLandFlagService.kt deleted file mode 100644 index 6845d87b..00000000 --- a/common/src/test/kotlin/net/onelitefeather/pandorascluster/api/TestLandFlagService.kt +++ /dev/null @@ -1,49 +0,0 @@ -package net.onelitefeather.pandorascluster.api - -import net.onelitefeather.pandorascluster.api.enums.LandRole -import net.onelitefeather.pandorascluster.api.land.flag.LandFlag -import net.onelitefeather.pandorascluster.api.service.LandFlagService -import net.onelitefeather.pandorascluster.database.service.DatabaseLandFlagService -import org.junit.Test -import kotlin.test.assertNotNull - -class TestLandFlagService { - - private val api: PandorasClusterApi = TestPandorasClusterApiImpl() - private val landFlagService: LandFlagService = DatabaseLandFlagService(api.getDatabaseService(), api.getLandService()) - private val testLandService: TestLandService = TestLandService() - - @Test - fun testAddLandFlag() { - testLandService.testLandCreation() - val land = api.getLandService().getLand(mainChunk) - assertNotNull(land) - landFlagService.addLandFlag(LandFlag.POTION_SPLASH, LandRole.MEMBER, land) - landFlagService.addLandFlag(LandFlag.ENTITY_LEASH, LandRole.VISITOR, land) - landFlagService.addLandFlag(LandFlag.VILLAGER_INTERACT, LandRole.ADMIN, land) - } - - @Test - fun testRemoveLandFlag() { - - testLandService.testLandCreation() - val land = api.getLandService().getLand(mainChunk) - assertNotNull(land) - - val landFlag = land.getFlag(LandFlag.ENTITY_LEASH) - assertNotNull(landFlag) - landFlagService.removeLandFlag(landFlag, land) - } - - @Test - fun testUpdateLandFlag() { - - testLandService.testLandCreation() - val land = api.getLandService().getLand(mainChunk) - assertNotNull(land) - - val flag = land.getFlag(LandFlag.POTION_SPLASH) - assertNotNull(flag) - landFlagService.updateLandFlag(flag.copy(role = LandRole.ADMIN), land) - } -} \ No newline at end of file diff --git a/common/src/test/kotlin/net/onelitefeather/pandorascluster/api/TestLandPlayerService.kt b/common/src/test/kotlin/net/onelitefeather/pandorascluster/api/TestLandPlayerService.kt deleted file mode 100644 index 75650312..00000000 --- a/common/src/test/kotlin/net/onelitefeather/pandorascluster/api/TestLandPlayerService.kt +++ /dev/null @@ -1,73 +0,0 @@ -package net.onelitefeather.pandorascluster.api - -import net.onelitefeather.pandorascluster.api.enums.LandRole -import net.onelitefeather.pandorascluster.api.service.LandPlayerService -import net.onelitefeather.pandorascluster.api.service.LandService -import org.junit.Test -import java.util.* -import kotlin.test.assertNotNull -import kotlin.test.assertTrue - -class TestLandPlayerService { - - private val api: PandorasClusterApi = TestPandorasClusterApiImpl() - private val landService: LandService = api.getLandService() - private val landPlayerService: LandPlayerService = api.getLandPlayerService() - - private val testLandService = TestLandService() - - private val uuid = UUID.fromString("df7c66a6-7876-44c2-9abd-9bd33f7d3d9e") - - @Test - fun testCreateLandPlayer() { - val playerName = "theShadowsDust" - if(landPlayerService.playerExists(uuid)) return - assertTrue { landPlayerService.createPlayer(uuid, playerName) } - } - - @Test - fun testUpdateLandPlayer() { - val landPlayer = landPlayerService.getLandPlayer(uuid) - assertNotNull(landPlayer) - landPlayerService.updateLandPlayer(landPlayer.copy(name = "theEvilReaper")) - } - - @Test - fun testAddLandMember() { - testLandService.testLandCreation() - val land = landService.getLand(mainChunk) - assertNotNull(land) - - val landPlayer = landPlayerService.getLandPlayer(uuid) - assertNotNull(landPlayer) - - landPlayerService.addLandMember(land, landPlayer, LandRole.MEMBER) - } - - @Test - fun testUpdateLandMember() { - testLandService.testLandCreation() - val land = landService.getLand(mainChunk) - assertNotNull(land) - - val member = landPlayerService.getLandMember(land, uuid) - assertNotNull(member) - - landPlayerService.updateLandMember(land, member.copy(role = LandRole.TRUSTED)) - } - - @Test - fun testRemoveLandMember() { - val land = landService.getLand(mainChunk) - assertNotNull(land) - - val member = landPlayerService.getLandMember(land, uuid) - assertNotNull(member) - landPlayerService.removeLandMember(member) - } - - @Test - fun testDeleteLandPlayer() { - landPlayerService.deletePlayer(uuid) - } -} \ No newline at end of file diff --git a/common/src/test/kotlin/net/onelitefeather/pandorascluster/api/TestLandService.kt b/common/src/test/kotlin/net/onelitefeather/pandorascluster/api/TestLandService.kt deleted file mode 100644 index 738ae882..00000000 --- a/common/src/test/kotlin/net/onelitefeather/pandorascluster/api/TestLandService.kt +++ /dev/null @@ -1,91 +0,0 @@ -package net.onelitefeather.pandorascluster.api - -import net.onelitefeather.pandorascluster.api.chunk.ClaimedChunk -import net.onelitefeather.pandorascluster.api.service.LandService -import org.junit.Test -import kotlin.test.assertNotEquals -import kotlin.test.assertNotNull -import kotlin.test.assertTrue - -class TestLandService { - - private val api: PandorasClusterApi = TestPandorasClusterApiImpl() - private val landService: LandService = api.getLandService() - - @Test - fun testCreateLandOwner() { - if (api.getLandPlayerService().playerExists(landOwnerUUID)) return - assertTrue(api.getLandPlayerService().createPlayer(landOwnerUUID, "theShadowsDust")) - } - - @Test - fun testLandCreation() { - val landPlayer = api.getLandPlayerService().getLandPlayer(landOwnerUUID) - assertNotNull(landPlayer) - - val land = landService.createLand(landPlayer, landHome, mainChunk, "world") - assertNotNull(land) - } - - @Test - fun testUpdateLandHome() { - - val owner = api.getLandPlayerService().getLandPlayer(landOwnerUUID) - assertNotNull(owner) - - val land = landService.getLand(owner) - assertNotNull(land) - - landService.updateLandHome(updatedHome.copy(land.home?.id), landOwnerUUID) - assertNotEquals(updatedHome, land.home) - } - - @Test - fun testisChunkClaimed() { - assertTrue(landService.isChunkClaimed(mainChunk)) - } - - @Test - fun testhasPlayerLand() { - val owner = api.getLandPlayerService().getLandPlayer(landOwnerUUID) - assertNotNull(owner) - assertTrue(landService.hasPlayerLand(owner)) - } - - @Test - fun testAddAndRemoveChunk() { - - val owner = api.getLandPlayerService().getLandPlayer(landOwnerUUID) - assertNotNull(owner) - - val land = landService.getLand(owner) - assertNotNull(land) - - val claimedChunk = ClaimedChunk(null, -random.nextLong(randomBound)) - landService.addClaimedChunk(claimedChunk, land) - - val chunk = landService.getClaimedChunk(claimedChunk.chunkIndex) - assertNotNull(chunk) - assertTrue(landService.removeClaimedChunk(chunk.chunkIndex)) - } - - @Test - fun testgetLand() { - - - val land = landService.getLand(mainChunk) - println("land = $land") - assertNotNull(land) - - val ownerByName = api.getLandPlayerService().getLandPlayer("theShadowsDust") - assertNotNull(ownerByName) - assertNotNull(landService.getLand(ownerByName)) - } - - @Test - fun testUnclaimLand() { - val land = landService.getLand(mainChunk) - assertNotNull(land) - landService.unclaimLand(land) - } -} \ No newline at end of file diff --git a/common/src/test/kotlin/net/onelitefeather/pandorascluster/api/TestPandorasClusterApiImpl.kt b/common/src/test/kotlin/net/onelitefeather/pandorascluster/api/TestPandorasClusterApiImpl.kt deleted file mode 100644 index b5292966..00000000 --- a/common/src/test/kotlin/net/onelitefeather/pandorascluster/api/TestPandorasClusterApiImpl.kt +++ /dev/null @@ -1,39 +0,0 @@ -package net.onelitefeather.pandorascluster.api - -import net.onelitefeather.pandorascluster.api.service.* -import net.onelitefeather.pandorascluster.database.service.DatabaseLandFlagService -import net.onelitefeather.pandorascluster.database.service.DatabaseLandPlayerService -import net.onelitefeather.pandorascluster.database.service.DatabaseLandService - -class TestPandorasClusterApiImpl : PandorasClusterApi { - - private var databaseService: DatabaseService = TestDatabaseServiceImpl() - private lateinit var landPlayerService: LandPlayerService - private lateinit var landFlagService: LandFlagService - private lateinit var landService: LandService - private lateinit var staffNotification: StaffNotificationService - - init { - databaseService.connect("connection.cfg.xml") - if (databaseService.isRunning()) { - landService = DatabaseLandService(this, databaseService) - landFlagService = DatabaseLandFlagService(databaseService, landService) - landPlayerService = DatabaseLandPlayerService(databaseService, landService) - staffNotification = StaffNotificationService(this) - } - } - - override fun getDatabaseStorageService(): LandService = landService - - override fun getLandPlayerService(): LandPlayerService = landPlayerService - - override fun getDatabaseService(): DatabaseService = databaseService - - override fun getLandService(): LandService = landService - - override fun getLandFlagService(): LandFlagService = landFlagService - - override fun getStaffNotification(): StaffNotificationService = staffNotification - - -} \ No newline at end of file diff --git a/common/src/test/kotlin/net/onelitefeather/pandorascluster/api/constants.kt b/common/src/test/kotlin/net/onelitefeather/pandorascluster/api/constants.kt deleted file mode 100644 index 673d882a..00000000 --- a/common/src/test/kotlin/net/onelitefeather/pandorascluster/api/constants.kt +++ /dev/null @@ -1,13 +0,0 @@ -package net.onelitefeather.pandorascluster.api - -import net.onelitefeather.pandorascluster.api.chunk.ClaimedChunk -import net.onelitefeather.pandorascluster.api.position.HomePosition -import java.util.* - -val updatedHome = HomePosition(null, 185.0, 27.0, 75.0, 0.0F, 0.0F) -val landHome = HomePosition(null, 180.0, 25.0, 60.0, 0.0F, 0.0F) -val mainChunk = ClaimedChunk(null, -12455436) -val landOwnerUUID: UUID = UUID.fromString("df7c66a6-7876-44c2-9abd-9bd33f7d3d9e") - -const val randomBound = 199999999L -val random = Random() \ No newline at end of file diff --git a/common/src/test/resources/connection.cfg.xml b/common/src/test/resources/connection.cfg.xml index 57929a0b..1ffe126b 100644 --- a/common/src/test/resources/connection.cfg.xml +++ b/common/src/test/resources/connection.cfg.xml @@ -4,25 +4,19 @@ "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> - org.postgresql.Driver - jdbc:postgresql://localhost:5432/pandoras_cluster - PUBLIC - pandoras_cluster - pandoras_cluster + org.h2.Driver + jdbc:h2:mem:pandoras;DB_CLOSE_DELAY=-1;MODE=PostgreSQL + sa + - 1 - org.hibernate.dialect.PostgreSQLDialect + org.hibernate.dialect.H2Dialect false false - - update + create-drop - org.hibernate.cache.internal.NoCacheProvider - - - \ No newline at end of file + diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index 29d023df..5598d0ed 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -3,7 +3,6 @@ plugins { alias(libs.plugins.run.paper) alias(libs.plugins.plugin.yml) alias(libs.plugins.shadow) - alias(libs.plugins.liquibase) `maven-publish` } diff --git a/plugin/src/main/java/net/onelitefeather/pandorascluster/PandorasClusterPlugin.java b/plugin/src/main/java/net/onelitefeather/pandorascluster/PandorasClusterPlugin.java index 21c15ad6..65378bfb 100644 --- a/plugin/src/main/java/net/onelitefeather/pandorascluster/PandorasClusterPlugin.java +++ b/plugin/src/main/java/net/onelitefeather/pandorascluster/PandorasClusterPlugin.java @@ -15,7 +15,13 @@ public class PandorasClusterPlugin extends JavaPlugin { @Override public void onEnable() { - this.pandorasCluster = new PandorasClusterImpl(); + try { + this.pandorasCluster = new PandorasClusterImpl(); + } catch (IllegalStateException e) { + getLogger().log(java.util.logging.Level.SEVERE, "PandorasCluster failed to initialize.", e); + getServer().getPluginManager().disablePlugin(this); + return; + } this.paperCommandService = new PaperCommandService(this); this.paperCommandService.registerCommands(); // Register the service for third-party plugins to use diff --git a/plugin/src/main/resources/hibernate.cfg.xml b/plugin/src/main/resources/hibernate.cfg.xml deleted file mode 100644 index 568ad592..00000000 --- a/plugin/src/main/resources/hibernate.cfg.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index c85b8526..d40f3d13 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -15,7 +15,6 @@ dependencyResolutionManagement { create("libs") { // Non Paper - version("liquibase", "2.2.2") version("guava", "33.3.1-jre") version("jaxb-runtime", "4.0.7") version("caffeine", "3.2.3") @@ -41,7 +40,7 @@ dependencyResolutionManagement { // Gradle Plugins version("plugin.yml", "0.6.0") version("run-paper", "3.0.2") - version("shadow", "8.1.1") + version("shadow", "9.4.1") // Paper library("paper", "io.papermc.paper", "paper-api").versionRef("paper") @@ -82,8 +81,7 @@ dependencyResolutionManagement { // Plugins plugin("plugin.yml", "net.minecrell.plugin-yml.paper").versionRef("plugin.yml") plugin("run.paper", "xyz.jpenilla.run-paper").versionRef("run-paper") - plugin("shadow", "com.github.johnrengelman.shadow").versionRef("shadow") - plugin("liquibase", "org.liquibase.gradle").versionRef("liquibase") + plugin("shadow", "com.gradleup.shadow").versionRef("shadow") } } }