mirror of
				https://github.com/IntellectualSites/PlotSquared.git
				synced 2025-10-27 23:53:45 +01:00 
			
		
		
		
	Compare commits
	
		
			63 Commits
		
	
	
		
			renovate/c
			...
			feat/visib
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 6d4cbb2df6 | ||
|   | d1a85982fb | ||
|   | 3446b913cd | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | 8b8fd6aab7 | ||
|   | 520bb64eca | ||
|   | 60d266b2d7 | ||
|   | 8deeef4f7d | ||
|   | 9b0b071c0c | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | 81a3f1098d | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | efc248dcdb | ||
|   | 476f3d328d | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | 69f5f88183 | ||
|   | 6df63f7fc7 | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | 295b8a0135 | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | fcc5bc5473 | ||
|   | 408b834376 | ||
|   | 986812b9e4 | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | 8d4333ad9d | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | 9ff9097ff9 | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | 1ef424a2f1 | ||
|   | 9fd96dbaa2 | ||
|   | b0a4e11c46 | ||
|   | 77bce43ace | ||
|   | cba1927cc7 | ||
|   | 3d19c5c2ad | ||
|   | e0eff15694 | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | 0bdeeea83b | ||
|   | 6f96daae56 | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | d1021d19da | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | ee589ac7f0 | ||
|   | 3b747ffecf | ||
|   | 4e5a2b9f96 | ||
|   | aeb4350ccb | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | 9609990832 | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | 0e4319b757 | ||
|   | c8f4907f77 | ||
|   | dcf98c2298 | ||
|   | ae59c7442f | ||
|   | 98708118d8 | ||
|   | 276d8f8e1e | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | 87f89541b5 | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | 93f6de7029 | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | 73d2686b17 | ||
|   | c446a95b07 | ||
|   | 3676e1df35 | ||
|   | 12e2705260 | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | 31e777a03a | ||
|   | 7f436c405b | ||
|   | 4d4d2ab087 | ||
|   | 91017acce4 | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | e90fd231d9 | ||
|   | cd9f0789de | ||
|   | 5f4c8d92df | ||
|   | 263cb47a21 | ||
|   | 005600c99e | ||
|   | 26bec7fe2f | ||
|   | f4b886d977 | ||
|   | c09d0d882e | ||
|   | 312cb2996c | ||
|   | f218902581 | ||
|   | f27009216c | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | dda52ebc2e | ||
|   | 9ac8d38bab | 
							
								
								
									
										3
									
								
								.github/ISSUE_TEMPLATE/bug_report.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.github/ISSUE_TEMPLATE/bug_report.yml
									
									
									
									
										vendored
									
									
								
							| @@ -27,10 +27,11 @@ body: | ||||
|       description: Which server version version you using? If your server version is not listed, it is not supported. Update to a supported version first. | ||||
|       multiple: false | ||||
|       options: | ||||
|         - '1.19.2' | ||||
|         - '1.19.1' | ||||
|         - '1.19' | ||||
|         - '1.18.2' | ||||
|         - '1.18.1' | ||||
|         - '1.18' | ||||
|         - '1.17.1' | ||||
|         - '1.16.5' | ||||
|     validations: | ||||
|   | ||||
| @@ -50,6 +50,7 @@ dependencies { | ||||
|     implementation(libs.arkitektonika) | ||||
|     implementation(libs.http4j) | ||||
|     implementation("com.intellectualsites.paster:Paster") | ||||
|     implementation("com.intellectualsites.informative-annotations:informative-annotations") | ||||
|  | ||||
|     // Adventure | ||||
|     implementation("net.kyori:adventure-platform-bukkit") | ||||
| @@ -87,6 +88,7 @@ tasks.named<ShadowJar>("shadowJar") { | ||||
|     relocate("javax.inject", "com.plotsquared.core.annotation.inject") | ||||
|     relocate("net.jcip", "com.plotsquared.core.annotations.jcip") | ||||
|     relocate("edu.umd.cs.findbugs", "com.plotsquared.core.annotations.findbugs") | ||||
|     relocate("com.intellectualsites.informative-annotations", "com.plotsquared.core.annotation.informative") | ||||
|  | ||||
|     // Get rid of all the libs which are 100% unused. | ||||
|     minimize() | ||||
| @@ -103,5 +105,6 @@ tasks { | ||||
|         opt.links("https://jd.adventure.kyori.net/api/4.9.3/") | ||||
|         opt.links("https://google.github.io/guice/api-docs/" + libs.guice.get().versionConstraint.toString() + "/javadoc/") | ||||
|         opt.links("https://checkerframework.org/api/") | ||||
|         opt.encoding("UTF-8") | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -41,6 +41,7 @@ import com.plotsquared.bukkit.listener.PlayerEventListener; | ||||
| import com.plotsquared.bukkit.listener.ProjectileEventListener; | ||||
| import com.plotsquared.bukkit.listener.ServerListener; | ||||
| import com.plotsquared.bukkit.listener.SingleWorldListener; | ||||
| import com.plotsquared.bukkit.listener.SpigotListener; | ||||
| import com.plotsquared.bukkit.listener.WorldEvents; | ||||
| import com.plotsquared.bukkit.placeholder.PAPIPlaceholders; | ||||
| import com.plotsquared.bukkit.placeholder.PlaceholderFormatter; | ||||
| @@ -360,6 +361,8 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl | ||||
|                 } else { | ||||
|                     getServer().getPluginManager().registerEvents(injector().getInstance(PaperListener.class), this); | ||||
|                 } | ||||
|             } else { | ||||
|                 getServer().getPluginManager().registerEvents(injector().getInstance(SpigotListener.class), this); | ||||
|             } | ||||
|             this.plotListener.startRunnable(); | ||||
|         } | ||||
| @@ -656,20 +659,15 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl | ||||
|             final @NonNull SQLiteUUIDService sqLiteUUIDService, | ||||
|             final @NonNull CacheUUIDService cacheUUIDService | ||||
|     ) { | ||||
|         // Load all uuids into a big chunky boi queue | ||||
|         final Queue<UUID> uuidQueue = new LinkedBlockingQueue<>(); | ||||
|         // Record all unique UUID's and put them into a queue | ||||
|         final Set<UUID> uuidSet = new HashSet<>(); | ||||
|         PlotSquared.get().forEachPlotRaw(plot -> { | ||||
|             final Set<UUID> uuids = new HashSet<>(); | ||||
|             uuids.add(plot.getOwnerAbs()); | ||||
|             uuids.addAll(plot.getMembers()); | ||||
|             uuids.addAll(plot.getTrusted()); | ||||
|             uuids.addAll(plot.getDenied()); | ||||
|             for (final UUID uuid : uuids) { | ||||
|                 if (!uuidQueue.contains(uuid)) { | ||||
|                     uuidQueue.add(uuid); | ||||
|                 } | ||||
|             } | ||||
|             uuidSet.add(plot.getOwnerAbs()); | ||||
|             uuidSet.addAll(plot.getMembers()); | ||||
|             uuidSet.addAll(plot.getTrusted()); | ||||
|             uuidSet.addAll(plot.getDenied()); | ||||
|         }); | ||||
|         final Queue<UUID> uuidQueue = new LinkedBlockingQueue<>(uuidSet); | ||||
|  | ||||
|         LOGGER.info("(UUID) {} UUIDs will be cached", uuidQueue.size()); | ||||
|  | ||||
| @@ -732,6 +730,11 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl | ||||
|         this.getServer().getPluginManager().disablePlugin(this); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void shutdownServer() { | ||||
|         getServer().shutdown(); | ||||
|     } | ||||
|  | ||||
|     private void registerCommands() { | ||||
|         final BukkitCommand bukkitCommand = new BukkitCommand(); | ||||
|         final PluginCommand plotCommand = getCommand("plots"); | ||||
|   | ||||
| @@ -109,6 +109,8 @@ import java.util.List; | ||||
| import java.util.Objects; | ||||
| import java.util.Set; | ||||
| import java.util.UUID; | ||||
| import java.util.stream.Collectors; | ||||
| import java.util.stream.Stream; | ||||
|  | ||||
| @SuppressWarnings("unused") | ||||
| public class BlockEventListener implements Listener { | ||||
| @@ -121,6 +123,11 @@ public class BlockEventListener implements Listener { | ||||
|             Material.TURTLE_EGG, | ||||
|             Material.TURTLE_SPAWN_EGG | ||||
|     ); | ||||
|     private static final Set<Material> SNOW = Stream.of(Material.values()) // needed as Tag.SNOW isn't present in 1.16.5 | ||||
|             .filter(material -> material.name().contains("SNOW")) | ||||
|             .filter(Material::isBlock) | ||||
|             .collect(Collectors.toUnmodifiableSet()); | ||||
|  | ||||
|     private final PlotAreaManager plotAreaManager; | ||||
|     private final WorldEdit worldEdit; | ||||
|  | ||||
| @@ -265,15 +272,9 @@ public class BlockEventListener implements Listener { | ||||
|         BukkitPlayer pp = BukkitUtil.adapt(player); | ||||
|         Plot plot = area.getPlot(location); | ||||
|         if (plot != null) { | ||||
|             if ((location.getY() >= area.getMaxBuildHeight() || location.getY() < area | ||||
|                     .getMinBuildHeight()) && !Permissions | ||||
|                     .hasPermission(pp, Permission.PERMISSION_ADMIN_BUILD_HEIGHT_LIMIT)) { | ||||
|             if (area.notifyIfOutsideBuildArea(pp, location.getY())) { | ||||
|                 event.setCancelled(true); | ||||
|                 pp.sendMessage( | ||||
|                         TranslatableCaption.of("height.height_limit"), | ||||
|                         Template.of("minHeight", String.valueOf(area.getMinBuildHeight())), | ||||
|                         Template.of("maxHeight", String.valueOf(area.getMaxBuildHeight())) | ||||
|                 ); | ||||
|                 return; | ||||
|             } | ||||
|             if (!plot.hasOwner()) { | ||||
|                 if (!Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_BUILD_UNOWNED)) { | ||||
| @@ -351,15 +352,9 @@ public class BlockEventListener implements Listener { | ||||
|                     event.setCancelled(true); | ||||
|                     return; | ||||
|                 } | ||||
|             } else if ((location.getY() >= area.getMaxBuildHeight() || location.getY() < area | ||||
|                     .getMinBuildHeight()) && !Permissions | ||||
|                     .hasPermission(plotPlayer, Permission.PERMISSION_ADMIN_BUILD_HEIGHT_LIMIT)) { | ||||
|             } else if (area.notifyIfOutsideBuildArea(plotPlayer, location.getY())) { | ||||
|                 event.setCancelled(true); | ||||
|                 plotPlayer.sendMessage( | ||||
|                         TranslatableCaption.of("height.height_limit"), | ||||
|                         Template.of("minHeight", String.valueOf(area.getMinBuildHeight())), | ||||
|                         Template.of("maxHeight", String.valueOf(area.getMaxBuildHeight())) | ||||
|                 ); | ||||
|                 return; | ||||
|             } | ||||
|             if (!plot.hasOwner()) { | ||||
|                 if (!Permissions | ||||
| @@ -447,6 +442,7 @@ public class BlockEventListener implements Listener { | ||||
|             case "TWISTING_VINES": | ||||
|             case "CAVE_VINES": | ||||
|             case "VINE": | ||||
|             case "GLOW_BERRIES": | ||||
|                 if (!plot.getFlag(VineGrowFlag.class)) { | ||||
|                     plot.debug("Vine could not grow because vine-grow = false"); | ||||
|                     event.setCancelled(true); | ||||
| @@ -537,11 +533,11 @@ public class BlockEventListener implements Listener { | ||||
|         if (plot == null) { | ||||
|             return; | ||||
|         } | ||||
|         if (location.getY() >= area.getMaxBuildHeight() || location.getY() < area.getMinBuildHeight()) { | ||||
|         if (!area.buildRangeContainsY(location.getY())) { | ||||
|             event.setCancelled(true); | ||||
|             return; | ||||
|         } | ||||
|         if (Tag.SNOW.isTagged(event.getNewState().getType())) { | ||||
|         if (SNOW.contains(event.getNewState().getType())) { | ||||
|             if (!plot.getFlag(SnowFormFlag.class)) { | ||||
|                 plot.debug("Snow could not form because snow-form = false"); | ||||
|                 event.setCancelled(true); | ||||
| @@ -573,7 +569,7 @@ public class BlockEventListener implements Listener { | ||||
|             return; | ||||
|         } | ||||
|         Class<? extends BooleanFlag<?>> flag; | ||||
|         if (Tag.SNOW.isTagged(event.getNewState().getType())) { | ||||
|         if (SNOW.contains(event.getNewState().getType())) { | ||||
|             flag = SnowFormFlag.class; | ||||
|         } else if (Tag.ICE.isTagged(event.getNewState().getType())) { | ||||
|             flag = IceFormFlag.class; | ||||
| @@ -690,7 +686,7 @@ public class BlockEventListener implements Listener { | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|         if (Tag.SNOW.isTagged(blockType)) { | ||||
|         if (SNOW.contains(blockType)) { | ||||
|             if (!plot.getFlag(SnowMeltFlag.class)) { | ||||
|                 plot.debug("Snow could not melt because snow-melt = false"); | ||||
|                 event.setCancelled(true); | ||||
| @@ -704,7 +700,7 @@ public class BlockEventListener implements Listener { | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|         if (Tag.CORAL_BLOCKS.isTagged(blockType) || Tag.CORALS.isTagged(blockType)) { | ||||
|         if (Tag.CORAL_BLOCKS.isTagged(blockType) || Tag.CORALS.isTagged(blockType) || Tag.WALL_CORALS.isTagged(blockType)) { | ||||
|             if (!plot.getFlag(CoralDryFlag.class)) { | ||||
|                 plot.debug("Coral could not dry because coral-dry = false"); | ||||
|                 event.setCancelled(true); | ||||
| @@ -739,7 +735,7 @@ public class BlockEventListener implements Listener { | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|         if (toLocation.getY() >= toArea.getMaxBuildHeight() || toLocation.getY() < toArea.getMinBuildHeight()) { | ||||
|         if (!toArea.buildRangeContainsY(toLocation.getY())) { | ||||
|             event.setCancelled(true); | ||||
|             return; | ||||
|         } | ||||
| @@ -813,6 +809,11 @@ public class BlockEventListener implements Listener { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if (!area.buildRangeContainsY(location.getY())) { | ||||
|             event.setCancelled(true); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         Plot plot = location.getOwnedPlot(); | ||||
|         if (plot == null || !plot.getFlag(CropGrowFlag.class)) { | ||||
|             if (plot != null) { | ||||
| @@ -856,15 +857,16 @@ public class BlockEventListener implements Listener { | ||||
|         } | ||||
|         for (Block block1 : event.getBlocks()) { | ||||
|             Location bloc = BukkitUtil.adapt(block1.getLocation()); | ||||
|             if (!area.contains(bloc.getX(), bloc.getZ()) || !area.contains( | ||||
|                     bloc.getX() + relative.getBlockX(), | ||||
|                     bloc.getZ() + relative.getBlockZ() | ||||
|             )) { | ||||
|             Location newLoc = bloc.add(relative.getBlockX(), relative.getBlockY(), relative.getBlockZ()); | ||||
|             if (!area.contains(bloc.getX(), bloc.getZ()) || !area.contains(newLoc)) { | ||||
|                 event.setCancelled(true); | ||||
|                 return; | ||||
|             } | ||||
|             if (!plot.equals(area.getOwnedPlot(bloc)) || !plot | ||||
|                     .equals(area.getOwnedPlot(bloc.add(relative.getBlockX(), relative.getBlockY(), relative.getBlockZ())))) { | ||||
|             if (!plot.equals(area.getOwnedPlot(bloc)) || !plot.equals(area.getOwnedPlot(newLoc))) { | ||||
|                 event.setCancelled(true); | ||||
|                 return; | ||||
|             } | ||||
|             if (!area.buildRangeContainsY(bloc.getY()) || !area.buildRangeContainsY(newLoc.getY())) { | ||||
|                 event.setCancelled(true); | ||||
|                 return; | ||||
|             } | ||||
| @@ -890,9 +892,8 @@ public class BlockEventListener implements Listener { | ||||
|             } | ||||
|             for (Block block1 : event.getBlocks()) { | ||||
|                 Location bloc = BukkitUtil.adapt(block1.getLocation()); | ||||
|                 if (bloc.isPlotArea() || bloc | ||||
|                         .add(relative.getBlockX(), relative.getBlockY(), relative.getBlockZ()) | ||||
|                         .isPlotArea()) { | ||||
|                 Location newLoc = bloc.add(relative.getBlockX(), relative.getBlockY(), relative.getBlockZ()); | ||||
|                 if (bloc.isPlotArea() || newLoc.isPlotArea()) { | ||||
|                     event.setCancelled(true); | ||||
|                     return; | ||||
|                 } | ||||
| @@ -906,15 +907,16 @@ public class BlockEventListener implements Listener { | ||||
|         } | ||||
|         for (Block block1 : event.getBlocks()) { | ||||
|             Location bloc = BukkitUtil.adapt(block1.getLocation()); | ||||
|             if (!area.contains(bloc.getX(), bloc.getZ()) || !area.contains( | ||||
|                     bloc.getX() + relative.getBlockX(), | ||||
|                     bloc.getZ() + relative.getBlockZ() | ||||
|             )) { | ||||
|             Location newLoc = bloc.add(relative.getBlockX(), relative.getBlockY(), relative.getBlockZ()); | ||||
|             if (!area.contains(bloc.getX(), bloc.getZ()) || !area.contains(newLoc)) { | ||||
|                 event.setCancelled(true); | ||||
|                 return; | ||||
|             } | ||||
|             if (!plot.equals(area.getOwnedPlot(bloc)) || !plot | ||||
|                     .equals(area.getOwnedPlot(bloc.add(relative.getBlockX(), relative.getBlockY(), relative.getBlockZ())))) { | ||||
|             if (!plot.equals(area.getOwnedPlot(bloc)) || !plot.equals(area.getOwnedPlot(newLoc))) { | ||||
|                 event.setCancelled(true); | ||||
|                 return; | ||||
|             } | ||||
|             if (!area.buildRangeContainsY(bloc.getY()) || !area.buildRangeContainsY(newLoc.getY())) { | ||||
|                 event.setCancelled(true); | ||||
|                 return; | ||||
|             } | ||||
| @@ -938,6 +940,11 @@ public class BlockEventListener implements Listener { | ||||
|                 Location location = BukkitUtil.adapt(event.getBlock().getRelative(targetFace).getLocation()); | ||||
|                 if (location.isPlotRoad()) { | ||||
|                     event.setCancelled(true); | ||||
|                     return; | ||||
|                 } | ||||
|                 PlotArea area = location.getPlotArea(); | ||||
|                 if (area != null && !area.buildRangeContainsY(location.getY())) { | ||||
|                     event.setCancelled(true); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| @@ -977,6 +984,10 @@ public class BlockEventListener implements Listener { | ||||
|                 Plot plot = area.getOwnedPlot(location); | ||||
|                 if (!Objects.equals(plot, origin)) { | ||||
|                     event.getBlocks().remove(i); | ||||
|                     continue; | ||||
|                 } | ||||
|                 if (!area.buildRangeContainsY(location.getY())) { | ||||
|                     event.getBlocks().remove(i); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| @@ -1068,6 +1079,10 @@ public class BlockEventListener implements Listener { | ||||
|         Plot plot = area.getOwnedPlot(location1); | ||||
|         if (player != null) { | ||||
|             BukkitPlayer pp = BukkitUtil.adapt(player); | ||||
|             if (area.notifyIfOutsideBuildArea(pp, location1.getY())) { | ||||
|                 event.setCancelled(true); | ||||
|                 return; | ||||
|             } | ||||
|             if (plot == null) { | ||||
|                 if (!Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_BUILD_ROAD)) { | ||||
|                     pp.sendMessage( | ||||
| @@ -1175,7 +1190,10 @@ public class BlockEventListener implements Listener { | ||||
|                     return true; | ||||
|                 } | ||||
|                 Plot plot = area.getOwnedPlot(blockLocation); | ||||
|                 return !Objects.equals(plot, origin); | ||||
|                 if (!Objects.equals(plot, origin)) { | ||||
|                     return true; | ||||
|                 } | ||||
|                 return !area.buildRangeContainsY(location.getY()); | ||||
|             }); | ||||
|         } | ||||
|         if (blocks.isEmpty()) { | ||||
| @@ -1217,15 +1235,7 @@ public class BlockEventListener implements Listener { | ||||
|                 event.setCancelled(true); | ||||
|                 break; | ||||
|             } | ||||
|             if (Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_BUILD_HEIGHT_LIMIT)) { | ||||
|                 continue; | ||||
|             } | ||||
|             if (currentLocation.getY() >= area.getMaxBuildHeight() || currentLocation.getY() < area.getMinBuildHeight()) { | ||||
|                 pp.sendMessage( | ||||
|                         TranslatableCaption.of("height.height_limit"), | ||||
|                         Template.of("minHeight", String.valueOf(area.getMinBuildHeight())), | ||||
|                         Template.of("maxHeight", String.valueOf(area.getMaxBuildHeight())) | ||||
|                 ); | ||||
|             if (area.notifyIfOutsideBuildArea(pp, currentLocation.getY())) { | ||||
|                 event.setCancelled(true); | ||||
|                 break; | ||||
|             } | ||||
|   | ||||
| @@ -80,10 +80,19 @@ public class BlockEventListener117 implements Listener { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         BukkitPlayer plotPlayer = null; | ||||
|  | ||||
|         if (entity instanceof Player player) { | ||||
|             plotPlayer = BukkitUtil.adapt(player); | ||||
|             if (area.notifyIfOutsideBuildArea(plotPlayer, location.getY())) { | ||||
|                 event.setCancelled(true); | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         Plot plot = location.getOwnedPlot(); | ||||
|         if (plot == null || !plot.getFlag(MiscInteractFlag.class)) { | ||||
|             if (entity instanceof Player player) { | ||||
|                 BukkitPlayer plotPlayer = BukkitUtil.adapt(player); | ||||
|             if (plotPlayer != null) { | ||||
|                 if (plot != null) { | ||||
|                     if (!plot.isAdded(plotPlayer.getUUID())) { | ||||
|                         plot.debug(plotPlayer.getName() + " couldn't trigger sculk sensors because misc-interact = false"); | ||||
| @@ -115,12 +124,12 @@ public class BlockEventListener117 implements Listener { | ||||
|         PlotArea area = location.getPlotArea(); | ||||
|         if (area == null) { | ||||
|             for (int i = blocks.size() - 1; i >= 0; i--) { | ||||
|                 location = BukkitUtil.adapt(blocks.get(i).getLocation()); | ||||
|                 if (location.isPlotArea()) { | ||||
|                 Location blockLocation = BukkitUtil.adapt(blocks.get(i).getLocation()); | ||||
|                 blockLocation = BukkitUtil.adapt(blocks.get(i).getLocation()); | ||||
|                 if (blockLocation.isPlotArea()) { | ||||
|                     blocks.remove(i); | ||||
|                 } | ||||
|             } | ||||
|             return; | ||||
|         } else { | ||||
|             Plot origin = area.getOwnedPlot(location); | ||||
|             if (origin == null) { | ||||
| @@ -128,27 +137,19 @@ public class BlockEventListener117 implements Listener { | ||||
|                 return; | ||||
|             } | ||||
|             for (int i = blocks.size() - 1; i >= 0; i--) { | ||||
|                 location = BukkitUtil.adapt(blocks.get(i).getLocation()); | ||||
|                 if (!area.contains(location.getX(), location.getZ())) { | ||||
|                 Location blockLocation = BukkitUtil.adapt(blocks.get(i).getLocation()); | ||||
|                 if (!area.contains(blockLocation.getX(), blockLocation.getZ())) { | ||||
|                     blocks.remove(i); | ||||
|                     continue; | ||||
|                 } | ||||
|                 Plot plot = area.getOwnedPlot(location); | ||||
|                 Plot plot = area.getOwnedPlot(blockLocation); | ||||
|                 if (!Objects.equals(plot, origin)) { | ||||
|                     event.getBlocks().remove(i); | ||||
|                     continue; | ||||
|                 } | ||||
|                 if (!area.buildRangeContainsY(location.getY())) { | ||||
|                     event.getBlocks().remove(i); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         Plot origin = area.getPlot(location); | ||||
|         if (origin == null) { | ||||
|             event.setCancelled(true); | ||||
|             return; | ||||
|         } | ||||
|         for (int i = blocks.size() - 1; i >= 0; i--) { | ||||
|             location = BukkitUtil.adapt(blocks.get(i).getLocation()); | ||||
|             Plot plot = area.getOwnedPlot(location); | ||||
|             if (!Objects.equals(plot, origin) && (!plot.isMerged() && !origin.isMerged())) { | ||||
|                 event.getBlocks().remove(i); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -126,16 +126,16 @@ public class EntitySpawnListener implements Listener { | ||||
|         Plot plot = location.getOwnedPlotAbs(); | ||||
|         EntityType type = entity.getType(); | ||||
|         if (plot == null) { | ||||
|             if (type == EntityType.DROPPED_ITEM) { | ||||
|                 if (Settings.Enabled_Components.KILL_ROAD_ITEMS) { | ||||
|                     event.setCancelled(true); | ||||
|                 } | ||||
|                 return; | ||||
|             } | ||||
|             if (!area.isMobSpawning()) { | ||||
|                 if (type == EntityType.PLAYER) { | ||||
|                     return; | ||||
|                 } | ||||
|                 if (type == EntityType.DROPPED_ITEM) { | ||||
|                     if (Settings.Enabled_Components.KILL_ROAD_ITEMS) { | ||||
|                         event.setCancelled(true); | ||||
|                     } | ||||
|                     return; | ||||
|                 } | ||||
|                 if (type.isAlive()) { | ||||
|                     event.setCancelled(true); | ||||
|                 } | ||||
|   | ||||
| @@ -18,6 +18,7 @@ | ||||
|  */ | ||||
| package com.plotsquared.bukkit.listener; | ||||
|  | ||||
| import com.destroystokyo.paper.event.block.BeaconEffectEvent; | ||||
| import com.destroystokyo.paper.event.entity.EntityPathfindEvent; | ||||
| import com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent; | ||||
| import com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent; | ||||
| @@ -36,8 +37,11 @@ import com.plotsquared.core.permissions.Permission; | ||||
| import com.plotsquared.core.player.PlotPlayer; | ||||
| import com.plotsquared.core.plot.Plot; | ||||
| import com.plotsquared.core.plot.PlotArea; | ||||
| import com.plotsquared.core.plot.flag.FlagContainer; | ||||
| import com.plotsquared.core.plot.flag.implementations.BeaconEffectsFlag; | ||||
| import com.plotsquared.core.plot.flag.implementations.DoneFlag; | ||||
| import com.plotsquared.core.plot.flag.implementations.ProjectilesFlag; | ||||
| import com.plotsquared.core.plot.flag.types.BooleanFlag; | ||||
| import com.plotsquared.core.plot.world.PlotAreaManager; | ||||
| import com.plotsquared.core.util.Permissions; | ||||
| import net.kyori.adventure.text.minimessage.Template; | ||||
| @@ -229,17 +233,17 @@ public class PaperListener implements Listener { | ||||
|         Plot plot = location.getOwnedPlotAbs(); | ||||
|         if (plot == null) { | ||||
|             EntityType type = event.getType(); | ||||
|             // PreCreatureSpawnEvent **should** not be called for DROPPED_ITEM, just for the sake of consistency | ||||
|             if (type == EntityType.DROPPED_ITEM) { | ||||
|                 if (Settings.Enabled_Components.KILL_ROAD_ITEMS) { | ||||
|                     event.setCancelled(true); | ||||
|                 } | ||||
|                 return; | ||||
|             } | ||||
|             if (!area.isMobSpawning()) { | ||||
|                 if (type == EntityType.PLAYER) { | ||||
|                     return; | ||||
|                 } | ||||
|                 if (type == EntityType.DROPPED_ITEM) { | ||||
|                     if (Settings.Enabled_Components.KILL_ROAD_ITEMS) { | ||||
|                         event.setShouldAbortSpawn(true); | ||||
|                         event.setCancelled(true); | ||||
|                     } | ||||
|                     return; | ||||
|                 } | ||||
|                 if (type.isAlive()) { | ||||
|                     event.setShouldAbortSpawn(true); | ||||
|                     event.setCancelled(true); | ||||
| @@ -400,4 +404,50 @@ public class PaperListener implements Listener { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @EventHandler(ignoreCancelled = true) | ||||
|     public void onBeaconEffect(final BeaconEffectEvent event) { | ||||
|         Block block = event.getBlock(); | ||||
|         Location beaconLocation = BukkitUtil.adapt(block.getLocation()); | ||||
|         Plot beaconPlot = beaconLocation.getPlot(); | ||||
|  | ||||
|         PlotArea area = beaconLocation.getPlotArea(); | ||||
|         if (area == null) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         Player player = event.getPlayer(); | ||||
|         Location playerLocation = BukkitUtil.adapt(player.getLocation()); | ||||
|  | ||||
|         PlotPlayer<Player> plotPlayer = BukkitUtil.adapt(player); | ||||
|         Plot playerStandingPlot = playerLocation.getPlot(); | ||||
|         if (playerStandingPlot == null) { | ||||
|             FlagContainer container = area.getRoadFlagContainer(); | ||||
|             if (!getBooleanFlagValue(container, BeaconEffectsFlag.class, true) || | ||||
|                     (beaconPlot != null && Settings.Enabled_Components.DISABLE_BEACON_EFFECT_OVERFLOW)) { | ||||
|                 event.setCancelled(true); | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         FlagContainer container = playerStandingPlot.getFlagContainer(); | ||||
|         boolean plotBeaconEffects = getBooleanFlagValue(container, BeaconEffectsFlag.class, true); | ||||
|         if (playerStandingPlot.equals(beaconPlot)) { | ||||
|             if (!plotBeaconEffects) { | ||||
|                 event.setCancelled(true); | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if (!plotBeaconEffects || Settings.Enabled_Components.DISABLE_BEACON_EFFECT_OVERFLOW) { | ||||
|             event.setCancelled(true); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private boolean getBooleanFlagValue(@NonNull FlagContainer container, | ||||
|                                         @NonNull Class<? extends BooleanFlag<?>> flagClass, | ||||
|                                         boolean defaultValue) { | ||||
|         BooleanFlag<?> flag = container.getFlag(flagClass); | ||||
|         return flag == null ? defaultValue : flag.getValue(); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -106,6 +106,7 @@ import org.bukkit.event.Listener; | ||||
| import org.bukkit.event.block.Action; | ||||
| import org.bukkit.event.entity.EntityPickupItemEvent; | ||||
| import org.bukkit.event.entity.EntityPlaceEvent; | ||||
| import org.bukkit.event.entity.EntityPotionEffectEvent; | ||||
| import org.bukkit.event.entity.PlayerDeathEvent; | ||||
| import org.bukkit.event.hanging.HangingBreakByEntityEvent; | ||||
| import org.bukkit.event.hanging.HangingPlaceEvent; | ||||
| @@ -142,23 +143,22 @@ import org.bukkit.inventory.meta.ItemMeta; | ||||
| import org.bukkit.metadata.FixedMetadataValue; | ||||
| import org.bukkit.metadata.MetadataValue; | ||||
| import org.bukkit.plugin.Plugin; | ||||
| import org.bukkit.potion.PotionEffect; | ||||
| import org.bukkit.util.Vector; | ||||
| import org.checkerframework.checker.nullness.qual.NonNull; | ||||
|  | ||||
| import java.lang.reflect.Field; | ||||
| import java.util.ArrayList; | ||||
| import java.util.HashSet; | ||||
| import java.util.List; | ||||
| import java.util.Locale; | ||||
| import java.util.Set; | ||||
| import java.util.UUID; | ||||
| import java.util.regex.Pattern; | ||||
|  | ||||
| /** | ||||
|  * Player Events involving plots. | ||||
|  */ | ||||
| @SuppressWarnings("unused") | ||||
| public class PlayerEventListener extends PlotListener implements Listener { | ||||
| public class PlayerEventListener implements Listener { | ||||
|  | ||||
|     private static final Set<Material> MINECARTS = Set.of( | ||||
|             Material.MINECART, | ||||
| @@ -177,6 +177,7 @@ public class PlayerEventListener extends PlotListener implements Listener { | ||||
|     private final EventDispatcher eventDispatcher; | ||||
|     private final WorldEdit worldEdit; | ||||
|     private final PlotAreaManager plotAreaManager; | ||||
|     private final PlotListener plotListener; | ||||
|     // To prevent recursion | ||||
|     private boolean tmpTeleport = true; | ||||
|     private Field fieldPlayer; | ||||
| @@ -196,12 +197,36 @@ public class PlayerEventListener extends PlotListener implements Listener { | ||||
|     public PlayerEventListener( | ||||
|             final @NonNull PlotAreaManager plotAreaManager, | ||||
|             final @NonNull EventDispatcher eventDispatcher, | ||||
|             final @NonNull WorldEdit worldEdit | ||||
|             final @NonNull WorldEdit worldEdit, | ||||
|             final @NonNull PlotListener plotListener | ||||
|     ) { | ||||
|         super(eventDispatcher); | ||||
|         this.eventDispatcher = eventDispatcher; | ||||
|         this.worldEdit = worldEdit; | ||||
|         this.plotAreaManager = plotAreaManager; | ||||
|         this.plotListener = plotListener; | ||||
|     } | ||||
|  | ||||
|     @EventHandler(ignoreCancelled = true) | ||||
|     public void onEffect(@NonNull EntityPotionEffectEvent event) { | ||||
|         if (Settings.Enabled_Components.DISABLE_BEACON_EFFECT_OVERFLOW || | ||||
|                 event.getCause() != EntityPotionEffectEvent.Cause.BEACON || | ||||
|                 !(event.getEntity() instanceof Player player)) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         UUID uuid = player.getUniqueId(); | ||||
|         PotionEffect effect = event.getNewEffect(); | ||||
|         if (effect == null) { | ||||
|             PotionEffect oldEffect = event.getOldEffect(); | ||||
|             if (oldEffect != null) { | ||||
|                 String name = oldEffect.getType().getName(); | ||||
|                 plotListener.addEffect(uuid, name, -1); | ||||
|             } | ||||
|         } else { | ||||
|             long expiresAt = System.currentTimeMillis() + effect.getDuration() * 50L; //Convert ticks to milliseconds | ||||
|             String name = effect.getType().getName(); | ||||
|             plotListener.addEffect(uuid, name, expiresAt); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @EventHandler | ||||
| @@ -354,7 +379,7 @@ public class PlayerEventListener extends PlotListener implements Listener { | ||||
|         if (area != null) { | ||||
|             Plot plot = area.getPlot(location); | ||||
|             if (plot != null) { | ||||
|                 plotEntry(pp, plot); | ||||
|                 plotListener.plotEntry(pp, plot); | ||||
|             } | ||||
|         } | ||||
|         // Delayed | ||||
| @@ -406,7 +431,7 @@ public class PlayerEventListener extends PlotListener implements Listener { | ||||
|                 PlotArea area = location.getPlotArea(); | ||||
|                 if (area == null) { | ||||
|                     if (lastPlot != null) { | ||||
|                         plotExit(pp, lastPlot); | ||||
|                         plotListener.plotExit(pp, lastPlot); | ||||
|                         lastPlotAccess.remove(); | ||||
|                     } | ||||
|                     try (final MetaDataAccess<Location> lastLocationAccess = | ||||
| @@ -540,7 +565,7 @@ public class PlayerEventListener extends PlotListener implements Listener { | ||||
|             if (now == null) { | ||||
|                 try (final MetaDataAccess<Boolean> kickAccess = | ||||
|                              pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_KICK)) { | ||||
|                     if (lastPlot != null && !plotExit(pp, lastPlot) && this.tmpTeleport && !kickAccess.get().orElse(false)) { | ||||
|                     if (lastPlot != null && !plotListener.plotExit(pp, lastPlot) && this.tmpTeleport && !kickAccess.get().orElse(false)) { | ||||
|                         pp.sendMessage( | ||||
|                                 TranslatableCaption.of("permission.no_permission_event"), | ||||
|                                 Template.of("node", String.valueOf(Permission.PERMISSION_ADMIN_EXIT_DENIED)) | ||||
| @@ -558,7 +583,7 @@ public class PlayerEventListener extends PlotListener implements Listener { | ||||
|                 } | ||||
|             } else if (now.equals(lastPlot)) { | ||||
|                 ForceFieldListener.handleForcefield(player, pp, now); | ||||
|             } else if (!plotEntry(pp, now) && this.tmpTeleport) { | ||||
|             } else if (!plotListener.plotEntry(pp, now) && this.tmpTeleport) { | ||||
|                 pp.sendMessage( | ||||
|                         TranslatableCaption.of("deny.no_enter"), | ||||
|                         Template.of("plot", now.toString()) | ||||
| @@ -630,7 +655,7 @@ public class PlayerEventListener extends PlotListener implements Listener { | ||||
|             if (plot == null) { | ||||
|                 try (final MetaDataAccess<Boolean> kickAccess = | ||||
|                              pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_KICK)) { | ||||
|                     if (lastPlot != null && !plotExit(pp, lastPlot) && this.tmpTeleport && !kickAccess.get().orElse(false)) { | ||||
|                     if (lastPlot != null && !plotListener.plotExit(pp, lastPlot) && this.tmpTeleport && !kickAccess.get().orElse(false)) { | ||||
|                         pp.sendMessage( | ||||
|                                 TranslatableCaption.of("permission.no_permission_event"), | ||||
|                                 Template.of("node", String.valueOf(Permission.PERMISSION_ADMIN_EXIT_DENIED)) | ||||
| @@ -648,7 +673,7 @@ public class PlayerEventListener extends PlotListener implements Listener { | ||||
|                 } | ||||
|             } else if (plot.equals(lastPlot)) { | ||||
|                 ForceFieldListener.handleForcefield(player, pp, plot); | ||||
|             } else if (!plotEntry(pp, plot) && this.tmpTeleport) { | ||||
|             } else if (!plotListener.plotEntry(pp, plot) && this.tmpTeleport) { | ||||
|                 pp.sendMessage( | ||||
|                         TranslatableCaption.of("deny.no_enter"), | ||||
|                         Template.of("plot", plot.toString()) | ||||
| @@ -795,7 +820,7 @@ public class PlayerEventListener extends PlotListener implements Listener { | ||||
|             lastLocationAccess.remove(); | ||||
|         } | ||||
|         if (plot != null) { | ||||
|             plotExit(pp, plot); | ||||
|             plotListener.plotExit(pp, plot); | ||||
|         } | ||||
|         if (this.worldEdit != null) { | ||||
|             if (!Permissions.hasPermission(pp, Permission.PERMISSION_WORLDEDIT_BYPASS)) { | ||||
| @@ -809,7 +834,7 @@ public class PlayerEventListener extends PlotListener implements Listener { | ||||
|         if (location.isPlotArea()) { | ||||
|             plot = location.getPlot(); | ||||
|             if (plot != null) { | ||||
|                 plotEntry(pp, plot); | ||||
|                 plotListener.plotEntry(pp, plot); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @@ -1282,7 +1307,7 @@ public class PlayerEventListener extends PlotListener implements Listener { | ||||
|         TaskManager.removeFromTeleportQueue(event.getPlayer().getName()); | ||||
|         BukkitPlayer pp = BukkitUtil.adapt(event.getPlayer()); | ||||
|         pp.unregister(); | ||||
|         this.logout(pp.getUUID()); | ||||
|         plotListener.logout(pp.getUUID()); | ||||
|     } | ||||
|  | ||||
|     @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) | ||||
| @@ -1719,6 +1744,7 @@ public class PlayerEventListener extends PlotListener implements Listener { | ||||
|         if (PlotSquared.get().getPlotAreaManager().getPlotAreasSet(world).size() == 0) { | ||||
|             return; | ||||
|         } | ||||
|         BukkitPlayer pp = (event.getEntity() instanceof Player player) ? BukkitUtil.adapt(player) : null; | ||||
|         int minX = Integer.MAX_VALUE; | ||||
|         int maxX = Integer.MIN_VALUE; | ||||
|         int minZ = Integer.MAX_VALUE; | ||||
| @@ -1740,6 +1766,10 @@ public class PlayerEventListener extends PlotListener implements Listener { | ||||
|             if (area == null) { | ||||
|                 continue; | ||||
|             } | ||||
|             if (area.notifyIfOutsideBuildArea(pp, location.getY())) { | ||||
|                 event.setCancelled(true); | ||||
|                 return; | ||||
|             } | ||||
|             Plot plot = location.getOwnedPlot(); | ||||
|             if (plot == null) { | ||||
|                 if (area.isRoadFlags() && area.getRoadFlag(DenyPortalsFlag.class)) { | ||||
|   | ||||
| @@ -89,7 +89,7 @@ public class ProjectileEventListener implements Listener { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @EventHandler | ||||
|     @EventHandler(ignoreCancelled = true) | ||||
|     public void onProjectileLaunch(ProjectileLaunchEvent event) { | ||||
|         Projectile entity = event.getEntity(); | ||||
|         ProjectileSource shooter = entity.getShooter(); | ||||
| @@ -149,6 +149,18 @@ public class ProjectileEventListener implements Listener { | ||||
|         Plot plot = area.getPlot(location); | ||||
|         ProjectileSource shooter = entity.getShooter(); | ||||
|         if (shooter instanceof Player) { | ||||
|             if (!((Player) shooter).isOnline()) { | ||||
|                 if (plot != null) { | ||||
|                     if (plot.isAdded(((Player) shooter).getUniqueId()) || plot.getFlag(ProjectilesFlag.class)) { | ||||
|                         return; | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 entity.remove(); | ||||
|                 event.setCancelled(true); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             PlotPlayer<?> pp = BukkitUtil.adapt((Player) shooter); | ||||
|             if (plot == null) { | ||||
|                 if (!Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_PROJECTILE_UNOWNED)) { | ||||
|   | ||||
| @@ -0,0 +1,57 @@ | ||||
| /* | ||||
|  * PlotSquared, a land and world management plugin for Minecraft. | ||||
|  * Copyright (C) IntellectualSites <https://intellectualsites.com> | ||||
|  * 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 <https://www.gnu.org/licenses/>. | ||||
|  */ | ||||
| package com.plotsquared.bukkit.listener; | ||||
|  | ||||
| import com.plotsquared.bukkit.util.BukkitUtil; | ||||
| import com.plotsquared.core.location.Location; | ||||
| import com.plotsquared.core.plot.Plot; | ||||
| import com.plotsquared.core.plot.flag.FlagContainer; | ||||
| import com.plotsquared.core.plot.flag.implementations.BeaconEffectsFlag; | ||||
| import org.bukkit.entity.Entity; | ||||
| import org.bukkit.event.EventHandler; | ||||
| import org.bukkit.event.Listener; | ||||
| import org.bukkit.event.entity.EntityPotionEffectEvent; | ||||
| import org.checkerframework.checker.nullness.qual.NonNull; | ||||
|  | ||||
| /** | ||||
|  * Fallback listener for paper events on spigot | ||||
|  */ | ||||
| public class SpigotListener implements Listener { | ||||
|  | ||||
|     @EventHandler(ignoreCancelled = true) | ||||
|     public void onEffect(@NonNull EntityPotionEffectEvent event) { | ||||
|         if (event.getCause() != EntityPotionEffectEvent.Cause.BEACON) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         Entity entity = event.getEntity(); | ||||
|         Location location = BukkitUtil.adapt(entity.getLocation()); | ||||
|         Plot plot = location.getPlot(); | ||||
|         if (plot == null) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         FlagContainer container = plot.getFlagContainer(); | ||||
|         BeaconEffectsFlag effectsEnabled = container.getFlag(BeaconEffectsFlag.class); | ||||
|         if (effectsEnabled != null && !effectsEnabled.getValue()) { | ||||
|             event.setCancelled(true); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -47,13 +47,13 @@ import org.bukkit.event.EventException; | ||||
| import org.bukkit.event.player.PlayerTeleportEvent; | ||||
| import org.bukkit.permissions.PermissionAttachmentInfo; | ||||
| import org.bukkit.plugin.RegisteredListener; | ||||
| import org.bukkit.potion.PotionEffectType; | ||||
| import org.checkerframework.checker.index.qual.NonNegative; | ||||
| import org.checkerframework.checker.nullness.qual.NonNull; | ||||
|  | ||||
| import java.util.Arrays; | ||||
| import java.util.Set; | ||||
| import java.util.UUID; | ||||
| import java.util.stream.Collectors; | ||||
|  | ||||
| import static com.sk89q.worldedit.world.gamemode.GameModes.ADVENTURE; | ||||
| import static com.sk89q.worldedit.world.gamemode.GameModes.CREATIVE; | ||||
| @@ -348,6 +348,14 @@ public class BukkitPlayer extends PlotPlayer<Player> { | ||||
|         return BukkitUtil.BUKKIT_AUDIENCES.player(this.player); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void removeEffect(@NonNull String name) { | ||||
|         PotionEffectType type = PotionEffectType.getByName(name); | ||||
|         if (type != null) { | ||||
|             player.removePotionEffect(type); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean canSee(final PlotPlayer<?> other) { | ||||
|         if (other instanceof ConsolePlayer) { | ||||
|   | ||||
| @@ -19,12 +19,12 @@ | ||||
| package com.plotsquared.bukkit.queue; | ||||
|  | ||||
| import com.google.common.base.Preconditions; | ||||
| import com.intellectualsites.annotations.DoNotUse; | ||||
| import com.plotsquared.bukkit.util.BukkitBlockUtil; | ||||
| import com.plotsquared.bukkit.util.BukkitUtil; | ||||
| import com.plotsquared.core.location.ChunkWrapper; | ||||
| import com.plotsquared.core.location.Location; | ||||
| import com.plotsquared.core.queue.ScopedQueueCoordinator; | ||||
| import com.plotsquared.core.util.AnnotationHelper; | ||||
| import com.plotsquared.core.util.ChunkUtil; | ||||
| import com.plotsquared.core.util.PatternUtil; | ||||
| import com.sk89q.worldedit.bukkit.BukkitAdapter; | ||||
| @@ -44,7 +44,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; | ||||
|  | ||||
| import java.util.Arrays; | ||||
|  | ||||
| @AnnotationHelper.ApiDescription(info = "Internal use only. Subject to changes at any time.") | ||||
| @DoNotUse | ||||
| public class GenChunk extends ScopedQueueCoordinator { | ||||
|  | ||||
|     public final Biome[] biomes; | ||||
|   | ||||
| @@ -58,6 +58,7 @@ import org.bukkit.block.BlockFace; | ||||
| import org.bukkit.block.Sign; | ||||
| import org.bukkit.block.data.Directional; | ||||
| import org.bukkit.block.data.type.WallSign; | ||||
| import org.bukkit.entity.Allay; | ||||
| import org.bukkit.entity.Ambient; | ||||
| import org.bukkit.entity.Animals; | ||||
| import org.bukkit.entity.AreaEffectCloud; | ||||
| @@ -437,6 +438,9 @@ public class BukkitUtil extends WorldUtil { | ||||
|                 allowedInterfaces.add(Animals.class); | ||||
|                 allowedInterfaces.add(WaterMob.class); | ||||
|                 allowedInterfaces.add(Ambient.class); | ||||
|                 if (PlotSquared.platform().serverVersion()[1] >= 19) { | ||||
|                     allowedInterfaces.add(Allay.class); | ||||
|                 } | ||||
|             } | ||||
|             case "tameable" -> allowedInterfaces.add(Tameable.class); | ||||
|             case "vehicle" -> allowedInterfaces.add(Vehicle.class); | ||||
|   | ||||
| @@ -43,6 +43,7 @@ dependencies { | ||||
|     api(libs.cloudServices) | ||||
|     api(libs.arkitektonika) | ||||
|     api("com.intellectualsites.paster:Paster") | ||||
|     api("com.intellectualsites.informative-annotations:informative-annotations") | ||||
| } | ||||
|  | ||||
| tasks.processResources { | ||||
| @@ -62,5 +63,7 @@ tasks { | ||||
|         opt.links("https://jd.adventure.kyori.net/api/4.9.3/") | ||||
|         opt.links("https://google.github.io/guice/api-docs/" + libs.guice.get().versionConstraint.toString() + "/javadoc/") | ||||
|         opt.links("https://checkerframework.org/api/") | ||||
|         opt.links("https://javadoc.io/doc/com.intellectualsites.informative-annotations/informative-annotations/latest/") | ||||
|         opt.encoding("UTF-8") | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -22,6 +22,7 @@ import cloud.commandframework.services.ServicePipeline; | ||||
| import com.google.inject.Injector; | ||||
| import com.google.inject.Key; | ||||
| import com.google.inject.TypeLiteral; | ||||
| import com.intellectualsites.annotations.DoNotUse; | ||||
| import com.plotsquared.core.backup.BackupManager; | ||||
| import com.plotsquared.core.configuration.caption.LocaleHolder; | ||||
| import com.plotsquared.core.generator.GeneratorWrapper; | ||||
| @@ -33,7 +34,6 @@ import com.plotsquared.core.permissions.PermissionHandler; | ||||
| import com.plotsquared.core.player.PlotPlayer; | ||||
| import com.plotsquared.core.plot.world.PlotAreaManager; | ||||
| import com.plotsquared.core.queue.GlobalBlockQueue; | ||||
| import com.plotsquared.core.util.AnnotationHelper; | ||||
| import com.plotsquared.core.util.ChunkManager; | ||||
| import com.plotsquared.core.util.EconHandler; | ||||
| import com.plotsquared.core.util.PlatformWorldManager; | ||||
| @@ -75,6 +75,11 @@ public interface PlotPlatform<P> extends LocaleHolder { | ||||
|      */ | ||||
|     void shutdown(); | ||||
|  | ||||
|     /** | ||||
|      * Completely shuts down the server. | ||||
|      */ | ||||
|     void shutdownServer(); | ||||
|  | ||||
|     /** | ||||
|      * Get the name of the plugin | ||||
|      * | ||||
| @@ -308,7 +313,7 @@ public interface PlotPlatform<P> extends LocaleHolder { | ||||
|      * @return worldedit implementations | ||||
|      * @since 6.3.0 | ||||
|      */ | ||||
|     @AnnotationHelper.ApiDescription(info = "Internal use only") | ||||
|     @DoNotUse | ||||
|     @NonNull String worldEditImplementations(); | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -197,6 +197,9 @@ public class PlotSquared { | ||||
|             this.loadCaptionMap(); | ||||
|         } catch (final Exception e) { | ||||
|             LOGGER.error("Failed to load caption map", e); | ||||
|             LOGGER.error("Shutting down server to prevent further issues"); | ||||
|             this.platform.shutdownServer(); | ||||
|             throw new RuntimeException("Abort loading PlotSquared"); | ||||
|         } | ||||
|  | ||||
|         // Setup the global flag container | ||||
| @@ -267,7 +270,7 @@ public class PlotSquared { | ||||
|             captionMap = this.captionLoader.loadAll(this.platform.getDirectory().toPath().resolve("lang")); | ||||
|         } else { | ||||
|             String fileName = "messages_" + Settings.Enabled_Components.DEFAULT_LOCALE + ".json"; | ||||
|             captionMap = this.captionLoader.loadSingle(this.platform.getDirectory().toPath().resolve("lang").resolve(fileName)); | ||||
|             captionMap = this.captionLoader.loadOrCreateSingle(this.platform.getDirectory().toPath().resolve("lang").resolve(fileName)); | ||||
|         } | ||||
|         this.captionMaps.put(TranslatableCaption.DEFAULT_NAMESPACE, captionMap); | ||||
|         LOGGER.info( | ||||
|   | ||||
| @@ -251,6 +251,7 @@ public class Auto extends SubCommand { | ||||
|                     TranslatableCaption.of("permission.no_permission"), | ||||
|                     Template.of("node", String.valueOf(Permission.PERMISSION_AUTO_MEGA)) | ||||
|             ); | ||||
|             return false; | ||||
|         } | ||||
|         if (!force && sizeX * sizeZ > Settings.Claim.MAX_AUTO_AREA) { | ||||
|             player.sendMessage( | ||||
|   | ||||
| @@ -181,6 +181,7 @@ public class Download extends SubCommand { | ||||
|                         schematicHandler.upload(compoundTag, null, null, new RunnableVal<>() { | ||||
|                             @Override | ||||
|                             public void run(URL value) { | ||||
|                                 plot.removeRunning(); | ||||
|                                 player.sendMessage( | ||||
|                                         TranslatableCaption.of("web.generation_link_success"), | ||||
|                                         Template.of("download", value.toString()), | ||||
|   | ||||
| @@ -462,6 +462,7 @@ public final class FlagCommand extends Command { | ||||
|             return; | ||||
|         } | ||||
|         final Plot plot = player.getLocation().getPlotAbs(); | ||||
|         final PlotFlag<?, ?> flagWithOldValue = plot.getFlagContainer().getFlag(flag.getClass()); | ||||
|         PlotFlagRemoveEvent event = eventDispatcher.callFlagRemove(flag, plot); | ||||
|         if (event.getEventResult() == Result.DENY) { | ||||
|             player.sendMessage( | ||||
| @@ -506,7 +507,7 @@ public final class FlagCommand extends Command { | ||||
|                     if (plot.removeFlag(flag)) { | ||||
|                         player.sendMessage(TranslatableCaption.of("flag.flag_removed"), Template.of("flag", args[0]), Template.of( | ||||
|                                 "value", | ||||
|                                 String.valueOf(flag) | ||||
|                                 String.valueOf(flagWithOldValue) | ||||
|                         )); | ||||
|                         return; | ||||
|                     } else { | ||||
| @@ -544,7 +545,7 @@ public final class FlagCommand extends Command { | ||||
|         } | ||||
|         player.sendMessage(TranslatableCaption.of("flag.flag_removed"), Template.of("flag", args[0]), Template.of( | ||||
|                 "value", | ||||
|                 String.valueOf(flag) | ||||
|                 String.valueOf(flagWithOldValue) | ||||
|         )); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -32,7 +32,6 @@ 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 com.plotsquared.core.uuid.UUIDMapping; | ||||
| import net.kyori.adventure.text.minimessage.Template; | ||||
|  | ||||
| import java.util.Collection; | ||||
| @@ -40,6 +39,7 @@ import java.util.Collections; | ||||
| import java.util.LinkedList; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.UUID; | ||||
| import java.util.concurrent.CompletableFuture; | ||||
| import java.util.concurrent.TimeoutException; | ||||
| import java.util.stream.Collectors; | ||||
| @@ -88,8 +88,8 @@ public class Grant extends Command { | ||||
|                                 Template.of("value", String.valueOf(uuids)) | ||||
|                         ); | ||||
|                     } else { | ||||
|                         final UUIDMapping uuid = uuids.toArray(new UUIDMapping[0])[0]; | ||||
|                         PlotPlayer<?> pp = PlotSquared.platform().playerManager().getPlayerIfExists(uuid.getUuid()); | ||||
|                         final UUID uuid = uuids.iterator().next(); | ||||
|                         PlotPlayer<?> pp = PlotSquared.platform().playerManager().getPlayerIfExists(uuid); | ||||
|                         if (pp != null) { | ||||
|                             try (final MetaDataAccess<Integer> access = pp.accessPersistentMetaData( | ||||
|                                     PlayerMetaDataKeys.PERSISTENT_GRANTED_PLOTS)) { | ||||
| @@ -103,7 +103,7 @@ public class Grant extends Command { | ||||
|                                 } | ||||
|                             } | ||||
|                         } else { | ||||
|                             DBFunc.getPersistentMeta(uuid.getUuid(), new RunnableVal<>() { | ||||
|                             DBFunc.getPersistentMeta(uuid, new RunnableVal<>() { | ||||
|                                 @Override | ||||
|                                 public void run(Map<String, byte[]> value) { | ||||
|                                     final byte[] array = value.get("grantedPlots"); | ||||
| @@ -128,7 +128,7 @@ public class Grant extends Command { | ||||
|                                         boolean replace = array != null; | ||||
|                                         String key = "grantedPlots"; | ||||
|                                         byte[] rawData = Ints.toByteArray(amount); | ||||
|                                         DBFunc.addPersistentMeta(uuid.getUuid(), key, rawData, replace); | ||||
|                                         DBFunc.addPersistentMeta(uuid, key, rawData, replace); | ||||
|                                         player.sendMessage( | ||||
|                                                 TranslatableCaption.of("grants.added"), | ||||
|                                                 Template.of("grants", String.valueOf(amount)) | ||||
|   | ||||
| @@ -26,6 +26,7 @@ import com.plotsquared.core.util.task.RunnableVal2; | ||||
| import com.plotsquared.core.util.task.RunnableVal3; | ||||
| import net.kyori.adventure.text.minimessage.Template; | ||||
|  | ||||
| import java.util.List; | ||||
| import java.util.concurrent.CompletableFuture; | ||||
|  | ||||
| @CommandDeclaration(command = "near", | ||||
| @@ -48,9 +49,13 @@ public class Near extends Command { | ||||
|         final Plot plot = check(player.getCurrentPlot(), TranslatableCaption.of("errors.not_in_plot")); | ||||
|         player.sendMessage( | ||||
|                 TranslatableCaption.of("near.plot_near"), | ||||
|                 Template.of("list", StringMan.join(plot.getPlayersInPlot(), ", ")) | ||||
|                 Template.of("list", StringMan.join(getPlayersInPlotVisible(plot, player), ", ")) | ||||
|         ); | ||||
|         return CompletableFuture.completedFuture(true); | ||||
|     } | ||||
|  | ||||
|     private List<PlotPlayer<?>> getPlayersInPlotVisible(Plot plot, PlotPlayer<?> executor) { | ||||
|         return plot.getPlayersInPlot().stream().filter(executor::canSee).toList(); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -115,8 +115,8 @@ public class Remove extends SubCommand { | ||||
|             } | ||||
|             if (count == 0) { | ||||
|                 player.sendMessage( | ||||
|                         TranslatableCaption.of("errors.invalid_player"), | ||||
|                         Template.of("value", args[0]) | ||||
|                         TranslatableCaption.of("member.player_not_removed"), | ||||
|                         Template.of("player", args[0]) | ||||
|                 ); | ||||
|             } else { | ||||
|                 player.sendMessage( | ||||
|   | ||||
| @@ -808,6 +808,8 @@ public class Settings extends Config { | ||||
|         ); | ||||
|         @Comment("Whether PlotSquared should hook into MvDWPlaceholderAPI or not") | ||||
|         public static boolean USE_MVDWAPI = true; | ||||
|         @Comment("Prevent cross plot beacon effects") | ||||
|         public static boolean DISABLE_BEACON_EFFECT_OVERFLOW = true; | ||||
|  | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -174,7 +174,7 @@ public final class CaptionLoader { | ||||
|     public @NonNull CaptionMap loadAll(final @NonNull Path directory) throws IOException { | ||||
|         final Map<Locale, CaptionMap> localeMaps = new HashMap<>(); | ||||
|         try (final Stream<Path> files = Files.list(directory)) { | ||||
|             final List<Path> captionFiles = files.filter(Files::isRegularFile).collect(Collectors.toList()); | ||||
|             final List<Path> captionFiles = files.filter(Files::isRegularFile).toList(); | ||||
|             for (Path file : captionFiles) { | ||||
|                 try { | ||||
|                     final CaptionMap localeMap = loadSingle(file); | ||||
| @@ -190,13 +190,14 @@ public final class CaptionLoader { | ||||
|  | ||||
|     /** | ||||
|      * Load a message file into a new CaptionMap. The file name must match | ||||
|      * the pattern {@code messages_<locale>.json} where {@code <locale>} | ||||
|      * is a valid {@link Locale} string. | ||||
|      * the pattern expected by the {@link #localeExtractor}. | ||||
|      * Note that this method does not attempt to create a new file. | ||||
|      * | ||||
|      * @param file The file to load | ||||
|      * @return A new CaptionMap containing the loaded messages | ||||
|      * @throws IOException              if the file couldn't be accessed or read successfully. | ||||
|      * @throws IllegalArgumentException if the file name doesn't match the specified format. | ||||
|      * @see #loadOrCreateSingle(Path) | ||||
|      */ | ||||
|     public @NonNull CaptionMap loadSingle(final @NonNull Path file) throws IOException { | ||||
|         final Locale locale = this.localeExtractor.apply(file); | ||||
| @@ -205,15 +206,43 @@ public final class CaptionLoader { | ||||
|             if (patch(map, locale)) { | ||||
|                 save(file, map); // update the file using the modified map | ||||
|             } | ||||
|             return new LocalizedCaptionMap(locale, map.entrySet().stream() | ||||
|                     .collect(Collectors.toMap( | ||||
|                                     entry -> TranslatableCaption.of(this.namespace, entry.getKey()), | ||||
|                                     Map.Entry::getValue | ||||
|                             ) | ||||
|                     )); | ||||
|             return new LocalizedCaptionMap(locale, mapToCaptions(map)); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Load a message file into a new CaptionMap. The file name must match | ||||
|      * the pattern expected by the {@link #localeExtractor}. | ||||
|      * If no file exists at the given path, this method will | ||||
|      * attempt to create one and fill it with default values. | ||||
|      * | ||||
|      * @param file The file to load | ||||
|      * @return A new CaptionMap containing the loaded messages | ||||
|      * @throws IOException              if the file couldn't be accessed or read successfully. | ||||
|      * @throws IllegalArgumentException if the file name doesn't match the specified format. | ||||
|      * @see #loadSingle(Path) | ||||
|      * @since 6.9.3 | ||||
|      */ | ||||
|     public @NonNull CaptionMap loadOrCreateSingle(final @NonNull Path file) throws IOException { | ||||
|         final Locale locale = this.localeExtractor.apply(file); | ||||
|         if (!Files.exists(file) ) { | ||||
|             Map<String, String> map = new LinkedHashMap<>(); | ||||
|             patch(map, locale); | ||||
|             save(file, map); | ||||
|             return new LocalizedCaptionMap(locale, mapToCaptions(map)); | ||||
|         } else { | ||||
|             return loadSingle(file); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private @NonNull Map<TranslatableCaption, String> mapToCaptions(Map<String, String> map) { | ||||
|         return map.entrySet().stream().collect( | ||||
|                 Collectors.toMap( | ||||
|                         entry -> TranslatableCaption.of(this.namespace, entry.getKey()), | ||||
|                         Map.Entry::getValue | ||||
|                 )); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Add missing entries to the given map. | ||||
|      * Entries are missing if the key exists in {@link #defaultLocale} but isn't present | ||||
|   | ||||
| @@ -20,6 +20,8 @@ package com.plotsquared.core.generator; | ||||
|  | ||||
| import com.google.inject.Inject; | ||||
| import com.google.inject.assistedinject.Assisted; | ||||
| import com.intellectualsites.annotations.DoNotUse; | ||||
| import com.intellectualsites.annotations.NotPublic; | ||||
| import com.plotsquared.core.PlotSquared; | ||||
| import com.plotsquared.core.configuration.ConfigurationSection; | ||||
| import com.plotsquared.core.configuration.Settings; | ||||
| @@ -33,7 +35,6 @@ import com.plotsquared.core.plot.PlotId; | ||||
| import com.plotsquared.core.plot.PlotManager; | ||||
| import com.plotsquared.core.plot.schematic.Schematic; | ||||
| import com.plotsquared.core.queue.GlobalBlockQueue; | ||||
| import com.plotsquared.core.util.AnnotationHelper; | ||||
| import com.plotsquared.core.util.FileUtils; | ||||
| import com.plotsquared.core.util.MathMan; | ||||
| import com.plotsquared.core.util.SchematicHandler; | ||||
| @@ -74,9 +75,6 @@ public class HybridPlotWorld extends ClassicPlotWorld { | ||||
|     public short PATH_WIDTH_UPPER; | ||||
|     public HashMap<Integer, BaseBlock[]> G_SCH; | ||||
|     public HashMap<Integer, BiomeType> G_SCH_B; | ||||
|     /** | ||||
|      * The Y level at which schematic generation will start, lowest of either road or plot schematic generation. | ||||
|      */ | ||||
|     public int SCHEM_Y; | ||||
|     private Location SIGN_LOCATION; | ||||
|     private File root = null; | ||||
| @@ -269,57 +267,33 @@ public class HybridPlotWorld extends ClassicPlotWorld { | ||||
|         int oddshift = (this.ROAD_WIDTH & 1); | ||||
|  | ||||
|         SCHEM_Y = schematicStartHeight(); | ||||
|  | ||||
|         // plotY and roadY are important to allow plot and/or road schematic "overflow" into each other without causing AIOOB | ||||
|         //  exceptions when attempting either to set blocks to, or get block from G_SCH | ||||
|         // Default plot schematic start height, normalized to the minimum height schematics are pasted from. | ||||
|         int plotY = PLOT_HEIGHT - SCHEM_Y; | ||||
|         int minRoadWall = Settings.Schematics.USE_WALL_IN_ROAD_SCHEM_HEIGHT ? Math.min(ROAD_HEIGHT, WALL_HEIGHT) : ROAD_HEIGHT; | ||||
|         // Default road schematic start height, normalized to the minimum height schematics are pasted from. | ||||
|         int roadY = minRoadWall - SCHEM_Y; | ||||
|  | ||||
|         int worldGenHeight = getMaxGenHeight() - getMinGenHeight() + 1; | ||||
|  | ||||
|         int maxSchematicHeight = 0; | ||||
|         int worldHeight = getMaxGenHeight() - getMinGenHeight() + 1; | ||||
|  | ||||
|         // SCHEM_Y should be normalised to the plot "start" height | ||||
|         if (schematic3 != null) { | ||||
|             if ((maxSchematicHeight = schematic3.getClipboard().getDimensions().getY()) == worldGenHeight) { | ||||
|                 SCHEM_Y = getMinGenHeight(); | ||||
|                 plotY = 0; | ||||
|             if (schematic3.getClipboard().getDimensions().getY() == worldHeight) { | ||||
|                 SCHEM_Y = plotY = 0; | ||||
|             } else if (!Settings.Schematics.PASTE_ON_TOP) { | ||||
|                 SCHEM_Y = getMinBuildHeight(); | ||||
|                 plotY = 0; | ||||
|                 SCHEM_Y = plotY = getMinBuildHeight() - getMinGenHeight(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (schematic1 != null) { | ||||
|             if ((maxSchematicHeight = Math.max( | ||||
|                     schematic1.getClipboard().getDimensions().getY(), | ||||
|                     maxSchematicHeight | ||||
|             )) == worldGenHeight) { | ||||
|                 SCHEM_Y = getMinGenHeight(); | ||||
|                 roadY = 0; // Road is the lowest schematic | ||||
|                 if (schematic3 != null && schematic3.getClipboard().getDimensions().getY() != worldGenHeight) { | ||||
|                     // Road is the lowest schematic. Normalize plotY to it. | ||||
|                     if (Settings.Schematics.PASTE_ON_TOP) { | ||||
|                         plotY = PLOT_HEIGHT - getMinGenHeight(); | ||||
|                     } else { | ||||
|                         plotY = getMinBuildHeight() - getMinGenHeight(); | ||||
|                     } | ||||
|             if (schematic1.getClipboard().getDimensions().getY() == worldHeight) { | ||||
|                 SCHEM_Y = roadY = getMinGenHeight(); | ||||
|                 if (schematic3 != null && schematic3.getClipboard().getDimensions().getY() != worldHeight | ||||
|                         && !Settings.Schematics.PASTE_ON_TOP) { | ||||
|                     plotY = PLOT_HEIGHT; | ||||
|                 } | ||||
|             } else if (!Settings.Schematics.PASTE_ROAD_ON_TOP) { | ||||
|                 if (SCHEM_Y == getMinGenHeight()) { // Only possible if plot schematic is enabled | ||||
|                     // Plot is still the lowest schematic, normalize roadY to it | ||||
|                     roadY = getMinBuildHeight() - getMinGenHeight(); | ||||
|                 } else if (schematic3 != null) { | ||||
|                     SCHEM_Y = getMinBuildHeight(); | ||||
|                     roadY = 0;// Road is the lowest schematic | ||||
|                     if (Settings.Schematics.PASTE_ON_TOP) { | ||||
|                         // Road is the lowest schematic. Normalize plotY to it. | ||||
|                         plotY = PLOT_HEIGHT - getMinBuildHeight(); | ||||
|                     } | ||||
|                     // If plot schematic is not paste-on-top, it will be from min build height thus plotY = 0 as well already. | ||||
|                 SCHEM_Y = roadY = getMinBuildHeight(); | ||||
|                 if (schematic3 != null && schematic3.getClipboard().getDimensions().getY() != worldHeight | ||||
|                         && !Settings.Schematics.PASTE_ON_TOP) { | ||||
|                     plotY = PLOT_HEIGHT; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| @@ -357,15 +331,17 @@ public class HybridPlotWorld extends ClassicPlotWorld { | ||||
|                                 y + min.getBlockY(), | ||||
|                                 z + min.getBlockZ() | ||||
|                         )); | ||||
|                         schem3PopulationNeeded |= id.hasNbtData(); | ||||
|                         addOverlayBlock( | ||||
|                                 (short) (x + shift + oddshift + centerShiftX), | ||||
|                                 (short) (y + plotY), | ||||
|                                 (short) (z + shift + oddshift + centerShiftZ), | ||||
|                                 id, | ||||
|                                 false, | ||||
|                                 maxSchematicHeight | ||||
|                         ); | ||||
|                         if (!id.getBlockType().getMaterial().isAir()) { | ||||
|                             schem3PopulationNeeded |= id.hasNbtData(); | ||||
|                             addOverlayBlock( | ||||
|                                     (short) (x + shift + oddshift + centerShiftX), | ||||
|                                     (short) (y + plotY), | ||||
|                                     (short) (z + shift + oddshift + centerShiftZ), | ||||
|                                     id, | ||||
|                                     false, | ||||
|                                     h3 | ||||
|                             ); | ||||
|                         } | ||||
|                     } | ||||
|                     if (blockArrayClipboard3.hasBiomes()) { | ||||
|                         BiomeType biome = blockArrayClipboard3.getBiome(BlockVector2.at( | ||||
| @@ -415,23 +391,18 @@ public class HybridPlotWorld extends ClassicPlotWorld { | ||||
|                             y + min.getBlockY(), | ||||
|                             z + min.getBlockZ() | ||||
|                     )); | ||||
|                     schem1PopulationNeeded |= id.hasNbtData(); | ||||
|                     addOverlayBlock( | ||||
|                             (short) (x - shift), | ||||
|                             (short) (y + roadY), | ||||
|                             (short) (z + shift + oddshift), | ||||
|                             id, | ||||
|                             false, | ||||
|                             maxSchematicHeight | ||||
|                     ); | ||||
|                     addOverlayBlock( | ||||
|                             (short) (z + shift + oddshift), | ||||
|                             (short) (y + roadY), | ||||
|                             (short) (shift - x + (oddshift - 1)), | ||||
|                             id, | ||||
|                             true, | ||||
|                             maxSchematicHeight | ||||
|                     ); | ||||
|                     if (!id.getBlockType().getMaterial().isAir()) { | ||||
|                         schem1PopulationNeeded |= id.hasNbtData(); | ||||
|                         addOverlayBlock((short) (x - shift), (short) (y + roadY), (short) (z + shift + oddshift), id, false, h1); | ||||
|                         addOverlayBlock( | ||||
|                                 (short) (z + shift + oddshift), | ||||
|                                 (short) (y + roadY), | ||||
|                                 (short) (shift - x + (oddshift - 1)), | ||||
|                                 id, | ||||
|                                 true, | ||||
|                                 h1 | ||||
|                         ); | ||||
|                     } | ||||
|                 } | ||||
|                 if (blockArrayClipboard1.hasBiomes()) { | ||||
|                     BiomeType biome = blockArrayClipboard1.getBiome(BlockVector2.at(x + min.getBlockX(), z + min.getBlockZ())); | ||||
| @@ -459,15 +430,10 @@ public class HybridPlotWorld extends ClassicPlotWorld { | ||||
|                             y + min.getBlockY(), | ||||
|                             z + min.getBlockZ() | ||||
|                     )); | ||||
|                     schem2PopulationNeeded |= id.hasNbtData(); | ||||
|                     addOverlayBlock( | ||||
|                             (short) (x - shift), | ||||
|                             (short) (y + roadY), | ||||
|                             (short) (z - shift), | ||||
|                             id, | ||||
|                             false, | ||||
|                             maxSchematicHeight | ||||
|                     ); | ||||
|                     if (!id.getBlockType().getMaterial().isAir()) { | ||||
|                         schem2PopulationNeeded |= id.hasNbtData(); | ||||
|                         addOverlayBlock((short) (x - shift), (short) (y + roadY), (short) (z - shift), id, false, h2); | ||||
|                     } | ||||
|                 } | ||||
|                 if (blockArrayClipboard2.hasBiomes()) { | ||||
|                     BiomeType biome = blockArrayClipboard2.getBiome(BlockVector2.at(x + min.getBlockX(), z + min.getBlockZ())); | ||||
| @@ -477,10 +443,6 @@ public class HybridPlotWorld extends ClassicPlotWorld { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @deprecated This method should not be available for public API usage and will be made private. | ||||
|      */ | ||||
|     @Deprecated(forRemoval = true, since = "TODO") | ||||
|     public void addOverlayBlock(short x, short y, short z, BaseBlock id, boolean rotate, int height) { | ||||
|         if (z < 0) { | ||||
|             z += this.SIZE; | ||||
| @@ -498,7 +460,7 @@ public class HybridPlotWorld extends ClassicPlotWorld { | ||||
|         int pair = MathMan.pair(x, z); | ||||
|         BaseBlock[] existing = this.G_SCH.computeIfAbsent(pair, k -> new BaseBlock[height]); | ||||
|         if (y >= height) { | ||||
|             if (y != lastOverlayHeightError) { | ||||
|             if (y > lastOverlayHeightError) { | ||||
|                 lastOverlayHeightError = y; | ||||
|                 LOGGER.error(String.format("Error adding overlay block. `y > height`. y=%s, height=%s", y, height)); | ||||
|             } | ||||
| @@ -507,10 +469,6 @@ public class HybridPlotWorld extends ClassicPlotWorld { | ||||
|         existing[y] = id; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @deprecated This method should not be available for public API usage and will be made private. | ||||
|      */ | ||||
|     @Deprecated(forRemoval = true, since = "TODO") | ||||
|     public void addOverlayBiome(short x, short z, BiomeType id) { | ||||
|         if (z < 0) { | ||||
|             z += this.SIZE; | ||||
| @@ -531,7 +489,7 @@ public class HybridPlotWorld extends ClassicPlotWorld { | ||||
|      * | ||||
|      * @since 6.9.0 | ||||
|      */ | ||||
|     @AnnotationHelper.ApiDescription(info = "Internal use only. Subject to changes at any time.") | ||||
|     @DoNotUse | ||||
|     public @Nullable List<Entity> getPlotSchematicEntities() { | ||||
|         return schem3Entities; | ||||
|     } | ||||
| @@ -541,7 +499,7 @@ public class HybridPlotWorld extends ClassicPlotWorld { | ||||
|      * | ||||
|      * @since 6.9.0 | ||||
|      */ | ||||
|     @AnnotationHelper.ApiDescription(info = "Internal use only. Subject to changes at any time.") | ||||
|     @DoNotUse | ||||
|     public @Nullable BlockVector3 getPlotSchematicMinPoint() { | ||||
|         return schem3MinPoint; | ||||
|     } | ||||
| @@ -551,7 +509,7 @@ public class HybridPlotWorld extends ClassicPlotWorld { | ||||
|      * | ||||
|      * @since 6.9.0 | ||||
|      */ | ||||
|     @AnnotationHelper.ApiDescription(info = "Internal use only. Subject to changes at any time.") | ||||
|     @DoNotUse | ||||
|     public boolean populationNeeded() { | ||||
|         return schem1PopulationNeeded || schem2PopulationNeeded || schem3PopulationNeeded; | ||||
|     } | ||||
|   | ||||
| @@ -189,13 +189,13 @@ public class HybridUtils { | ||||
|                 if (X == ctx) { | ||||
|                     maxX = tx & 15; | ||||
|                 } else { | ||||
|                     maxX = 16; | ||||
|                     maxX = 15; | ||||
|                 } | ||||
|                 int maxZ; | ||||
|                 if (Z == ctz) { | ||||
|                     maxZ = tz & 15; | ||||
|                 } else { | ||||
|                     maxZ = 16; | ||||
|                     maxZ = 15; | ||||
|                 } | ||||
|  | ||||
|                 int chunkBlockX = X << 4; | ||||
| @@ -221,7 +221,7 @@ public class HybridUtils { | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|             final Runnable run = () -> TaskManager.runTaskAsync(() -> { | ||||
|             final Runnable run = () -> { | ||||
|                 int size = width * length; | ||||
|                 int[] changes = new int[size]; | ||||
|                 int[] faces = new int[size]; | ||||
| @@ -296,7 +296,7 @@ public class HybridUtils { | ||||
|                 analysis.variety_sd = (int) (MathMan.getSD(variety, analysis.variety) * 100); | ||||
|                 whenDone.value = analysis; | ||||
|                 whenDone.run(); | ||||
|             }); | ||||
|             }; | ||||
|             queue.setCompleteTask(run); | ||||
|             queue.enqueue(); | ||||
|         }); | ||||
|   | ||||
| @@ -67,10 +67,13 @@ import com.sk89q.worldedit.world.item.ItemType; | ||||
| import com.sk89q.worldedit.world.item.ItemTypes; | ||||
| import net.kyori.adventure.text.minimessage.MiniMessage; | ||||
| import net.kyori.adventure.text.minimessage.Template; | ||||
| import org.checkerframework.checker.nullness.qual.NonNull; | ||||
| import org.checkerframework.checker.nullness.qual.Nullable; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.HashMap; | ||||
| import java.util.Iterator; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.Optional; | ||||
| import java.util.UUID; | ||||
| @@ -82,6 +85,7 @@ public class PlotListener { | ||||
|  | ||||
|     private final HashMap<UUID, Interval> feedRunnable = new HashMap<>(); | ||||
|     private final HashMap<UUID, Interval> healRunnable = new HashMap<>(); | ||||
|     private final Map<UUID, List<StatusEffect>> playerEffects = new HashMap<>(); | ||||
|  | ||||
|     private final EventDispatcher eventDispatcher; | ||||
|  | ||||
| @@ -131,6 +135,17 @@ public class PlotListener { | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if (!playerEffects.isEmpty()) { | ||||
|                 long currentTime = System.currentTimeMillis(); | ||||
|                 for (Iterator<Map.Entry<UUID, List<StatusEffect>>> iterator = | ||||
|                      playerEffects.entrySet().iterator(); iterator.hasNext(); ) { | ||||
|                     Map.Entry<UUID, List<StatusEffect>> entry = iterator.next(); | ||||
|                     List<StatusEffect> effects = entry.getValue(); | ||||
|                     effects.removeIf(effect -> currentTime > effect.expiresAt); | ||||
|                     if (effects.isEmpty()) iterator.remove(); | ||||
|                 } | ||||
|             } | ||||
|         }, TaskTime.seconds(1L)); | ||||
|     } | ||||
|  | ||||
| @@ -360,6 +375,17 @@ public class PlotListener { | ||||
|         try (final MetaDataAccess<Plot> lastPlot = player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { | ||||
|             final Plot previous = lastPlot.remove(); | ||||
|             this.eventDispatcher.callLeave(player, plot); | ||||
|  | ||||
|             List<StatusEffect> effects = playerEffects.remove(player.getUUID()); | ||||
|             if (effects != null) { | ||||
|                 long currentTime = System.currentTimeMillis(); | ||||
|                 effects.forEach(effect -> { | ||||
|                     if (currentTime <= effect.expiresAt) { | ||||
|                         player.removeEffect(effect.name); | ||||
|                     } | ||||
|                 }); | ||||
|             } | ||||
|  | ||||
|             if (plot.hasOwner()) { | ||||
|                 PlotArea pw = plot.getArea(); | ||||
|                 if (pw == null) { | ||||
| @@ -468,6 +494,23 @@ public class PlotListener { | ||||
|     public void logout(UUID uuid) { | ||||
|         feedRunnable.remove(uuid); | ||||
|         healRunnable.remove(uuid); | ||||
|         playerEffects.remove(uuid); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Marks an effect as a status effect that will be removed on leaving a plot | ||||
|      * @param uuid The uuid of the player the effect belongs to | ||||
|      * @param name The name of the status effect | ||||
|      * @param expiresAt The time when the effect expires | ||||
|      * @since 6.10.0 | ||||
|      */ | ||||
|     public void addEffect(@NonNull UUID uuid, @NonNull String name, long expiresAt) { | ||||
|         List<StatusEffect> effects = playerEffects.getOrDefault(uuid, new ArrayList<>()); | ||||
|         effects.removeIf(effect -> effect.name.equals(name)); | ||||
|         if (expiresAt != -1) { | ||||
|             effects.add(new StatusEffect(name, expiresAt)); | ||||
|         } | ||||
|         playerEffects.put(uuid, effects); | ||||
|     } | ||||
|  | ||||
|     private static class Interval { | ||||
| @@ -485,4 +528,13 @@ public class PlotListener { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     private record StatusEffect(@NonNull String name, long expiresAt) { | ||||
|  | ||||
|         private StatusEffect(@NonNull String name, long expiresAt) { | ||||
|                 this.name = name; | ||||
|                 this.expiresAt = expiresAt; | ||||
|             } | ||||
|  | ||||
|         } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -313,7 +313,7 @@ public sealed class Location extends BlockLoc implements Comparable<Location> pe | ||||
|     /** | ||||
|      * Get the absolute {@link Plot}, if any, that contains this location | ||||
|      * | ||||
|      * @return (Absolute) plot containing the location, or {code null} | ||||
|      * @return (Absolute) plot containing the location, or {@code null} | ||||
|      */ | ||||
|     public @Nullable Plot getPlotAbs() { | ||||
|         final PlotArea area = this.getPlotArea(); | ||||
| @@ -327,7 +327,7 @@ public sealed class Location extends BlockLoc implements Comparable<Location> pe | ||||
|     /** | ||||
|      * Get the {@link Plot}, if any, that contains this location | ||||
|      * | ||||
|      * @return plot containing the location, or {code null} | ||||
|      * @return plot containing the location, or {@code null} | ||||
|      */ | ||||
|     public @Nullable Plot getPlot() { | ||||
|         final PlotArea area = this.getPlotArea(); | ||||
|   | ||||
| @@ -18,7 +18,7 @@ | ||||
|  */ | ||||
| package com.plotsquared.core.location; | ||||
|  | ||||
| import com.plotsquared.core.util.AnnotationHelper; | ||||
| import com.intellectualsites.annotations.DoNotUse; | ||||
| import com.sk89q.worldedit.math.BlockVector3; | ||||
| import org.checkerframework.checker.nullness.qual.NonNull; | ||||
|  | ||||
| @@ -28,7 +28,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; | ||||
|  * | ||||
|  * @since 6.9.0 | ||||
|  */ | ||||
| @AnnotationHelper.ApiDescription(info = "Internal use only. Subject to changes at any time.") | ||||
| @DoNotUse | ||||
| public final class UncheckedWorldLocation extends Location { | ||||
|  | ||||
|     private final String worldName; | ||||
| @@ -54,7 +54,7 @@ public final class UncheckedWorldLocation extends Location { | ||||
|      * | ||||
|      * @since 6.9.0 | ||||
|      */ | ||||
|     @AnnotationHelper.ApiDescription(info = "Internal use only. Subject to changes at any time.") | ||||
|     @DoNotUse | ||||
|     public static @NonNull UncheckedWorldLocation at( | ||||
|             final @NonNull String world, final int x, final int y, final int z | ||||
|     ) { | ||||
| @@ -62,7 +62,7 @@ public final class UncheckedWorldLocation extends Location { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     @AnnotationHelper.ApiDescription(info = "Internal use only. Subject to changes at any time.") | ||||
|     @DoNotUse | ||||
|     public @NonNull String getWorldName() { | ||||
|         return this.worldName; | ||||
|     } | ||||
|   | ||||
| @@ -246,6 +246,10 @@ public class ConsolePlayer extends PlotPlayer<Actor> { | ||||
|         return PlotSquared.platform().consoleAudience(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void removeEffect(@NonNull String name) { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean canSee(final PlotPlayer<?> other) { | ||||
|         return true; | ||||
|   | ||||
| @@ -1016,6 +1016,14 @@ public abstract class PlotPlayer<P> implements CommandCaller, OfflinePlotPlayer, | ||||
|         return this.lockRepository; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Removes any effects present of the given type. | ||||
|      * | ||||
|      * @param name the name of the type to remove | ||||
|      * @since 6.10.0 | ||||
|      */ | ||||
|     public abstract void removeEffect(@NonNull String name); | ||||
|  | ||||
|     @FunctionalInterface | ||||
|     public interface PlotPlayerConverter<BaseObject> { | ||||
|  | ||||
|   | ||||
| @@ -457,7 +457,7 @@ public class Plot { | ||||
|      * that could alter the de facto owner of the plot. | ||||
|      * | ||||
|      * @return The plot owner of this particular (sub-)plot | ||||
|      * as stored in the database, if one exists. Else, null. | ||||
|      *         as stored in the database, if one exists. Else, null. | ||||
|      */ | ||||
|     public @Nullable UUID getOwnerAbs() { | ||||
|         return this.owner; | ||||
|   | ||||
| @@ -36,6 +36,7 @@ import com.plotsquared.core.location.BlockLoc; | ||||
| import com.plotsquared.core.location.Direction; | ||||
| import com.plotsquared.core.location.Location; | ||||
| import com.plotsquared.core.location.PlotLoc; | ||||
| import com.plotsquared.core.permissions.Permission; | ||||
| import com.plotsquared.core.player.ConsolePlayer; | ||||
| import com.plotsquared.core.player.MetaDataAccess; | ||||
| import com.plotsquared.core.player.PlayerMetaDataKeys; | ||||
| @@ -48,6 +49,7 @@ import com.plotsquared.core.plot.flag.implementations.DoneFlag; | ||||
| import com.plotsquared.core.queue.GlobalBlockQueue; | ||||
| import com.plotsquared.core.queue.QueueCoordinator; | ||||
| import com.plotsquared.core.util.MathMan; | ||||
| import com.plotsquared.core.util.Permissions; | ||||
| import com.plotsquared.core.util.PlotExpression; | ||||
| import com.plotsquared.core.util.RegionUtil; | ||||
| import com.plotsquared.core.util.StringMan; | ||||
| @@ -624,6 +626,38 @@ public abstract class PlotArea { | ||||
|                 getRegionAbs() == null || this.region.contains(location.getBlockVector3())); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get if the {@code PlotArea}'s build range (min build height -> max build height) contains the given y value | ||||
|      * | ||||
|      * @param y y height | ||||
|      * @return if build height contains y | ||||
|      */ | ||||
|     public boolean buildRangeContainsY(int y) { | ||||
|         return y >= minBuildHeight && y < maxBuildHeight; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Utility method to check if the player is attempting to place blocks outside the build area, and notify of this if the | ||||
|      * player does not have permissions. | ||||
|      * | ||||
|      * @param player Player to check | ||||
|      * @param y      y height to check | ||||
|      * @return true if outside build area with no permissions | ||||
|      * @since 6.9.1 | ||||
|      */ | ||||
|     public boolean notifyIfOutsideBuildArea(PlotPlayer<?> player, int y) { | ||||
|         if (!buildRangeContainsY(y) && !Permissions.hasPermission(player, Permission.PERMISSION_ADMIN_BUILD_HEIGHT_LIMIT)) { | ||||
|             player.sendMessage( | ||||
|                     TranslatableCaption.of("height.height_limit"), | ||||
|                     Template.of("minHeight", String.valueOf(minBuildHeight)), | ||||
|                     Template.of("maxHeight", String.valueOf(maxBuildHeight)) | ||||
|             ); | ||||
|             // Return true if "failed" as the method will always be inverted otherwise | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     public @NonNull Set<Plot> getPlotsAbs(final UUID uuid) { | ||||
|         if (uuid == null) { | ||||
|             return Collections.emptySet(); | ||||
|   | ||||
| @@ -20,8 +20,8 @@ package com.plotsquared.core.plot.flag; | ||||
|  | ||||
| import com.google.common.base.Preconditions; | ||||
| import com.google.common.collect.ImmutableMap; | ||||
| import com.intellectualsites.annotations.NotPublic; | ||||
| import com.plotsquared.core.configuration.caption.CaptionUtility; | ||||
| import com.plotsquared.core.util.AnnotationHelper; | ||||
| import org.apache.logging.log4j.LogManager; | ||||
| import org.apache.logging.log4j.Logger; | ||||
| import org.checkerframework.checker.nullness.qual.NonNull; | ||||
| @@ -32,7 +32,6 @@ import java.util.HashMap; | ||||
| import java.util.HashSet; | ||||
| import java.util.Locale; | ||||
| import java.util.Map; | ||||
| import java.util.Objects; | ||||
|  | ||||
| /** | ||||
|  * Container type for {@link PlotFlag plot flags}. | ||||
| @@ -353,7 +352,7 @@ public class FlagContainer { | ||||
|      * @return a new Runnable that cleans up once the FlagContainer isn't needed anymore. | ||||
|      * @since 6.0.10 | ||||
|      */ | ||||
|     @AnnotationHelper.ApiDescription(info = "This method should not be considered as public or API.") | ||||
|     @NotPublic | ||||
|     public Runnable createCleanupHook() { | ||||
|         return () -> GlobalFlagContainer.getInstance().unsubscribe(unknownsRef); | ||||
|     } | ||||
|   | ||||
| @@ -23,6 +23,7 @@ import com.plotsquared.core.plot.flag.implementations.AnalysisFlag; | ||||
| import com.plotsquared.core.plot.flag.implementations.AnimalAttackFlag; | ||||
| import com.plotsquared.core.plot.flag.implementations.AnimalCapFlag; | ||||
| import com.plotsquared.core.plot.flag.implementations.AnimalInteractFlag; | ||||
| import com.plotsquared.core.plot.flag.implementations.BeaconEffectsFlag; | ||||
| import com.plotsquared.core.plot.flag.implementations.BlockBurnFlag; | ||||
| import com.plotsquared.core.plot.flag.implementations.BlockIgnitionFlag; | ||||
| import com.plotsquared.core.plot.flag.implementations.BlockedCmdsFlag; | ||||
| @@ -137,6 +138,7 @@ public final class GlobalFlagContainer extends FlagContainer { | ||||
|         this.addFlag(AnimalAttackFlag.ANIMAL_ATTACK_FALSE); | ||||
|         this.addFlag(AnimalInteractFlag.ANIMAL_INTERACT_FALSE); | ||||
|         this.addFlag(BlockBurnFlag.BLOCK_BURN_FALSE); | ||||
|         this.addFlag(BeaconEffectsFlag.BEACON_EFFECT_TRUE); | ||||
|         this.addFlag(BlockIgnitionFlag.BLOCK_IGNITION_TRUE); | ||||
|         this.addFlag(ChatFlag.CHAT_FLAG_TRUE); | ||||
|         this.addFlag(CopperOxideFlag.COPPER_OXIDE_FALSE); | ||||
|   | ||||
| @@ -0,0 +1,39 @@ | ||||
| /* | ||||
|  * PlotSquared, a land and world management plugin for Minecraft. | ||||
|  * Copyright (C) IntellectualSites <https://intellectualsites.com> | ||||
|  * 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 <https://www.gnu.org/licenses/>. | ||||
|  */ | ||||
| package com.plotsquared.core.plot.flag.implementations; | ||||
|  | ||||
| import com.plotsquared.core.configuration.caption.TranslatableCaption; | ||||
| import com.plotsquared.core.plot.flag.types.BooleanFlag; | ||||
| import org.checkerframework.checker.nullness.qual.NonNull; | ||||
|  | ||||
| public class BeaconEffectsFlag extends BooleanFlag<BeaconEffectsFlag> { | ||||
|  | ||||
|     public static final BeaconEffectsFlag BEACON_EFFECT_TRUE = new BeaconEffectsFlag(true); | ||||
|     public static final BeaconEffectsFlag BEACON_EFFECT_FALSE = new BeaconEffectsFlag(false); | ||||
|  | ||||
|     private BeaconEffectsFlag(boolean value){ | ||||
|         super(value, TranslatableCaption.of("flags.flag_description_beacon_effect")); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected BeaconEffectsFlag flagOf(@NonNull final Boolean value) { | ||||
|         return value ? BEACON_EFFECT_TRUE : BEACON_EFFECT_FALSE; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -18,8 +18,8 @@ | ||||
|  */ | ||||
| package com.plotsquared.core.queue; | ||||
|  | ||||
| import com.intellectualsites.annotations.DoNotUse; | ||||
| import com.plotsquared.core.location.Location; | ||||
| import com.plotsquared.core.util.AnnotationHelper; | ||||
| import com.sk89q.jnbt.CompoundTag; | ||||
| import com.sk89q.worldedit.function.pattern.Pattern; | ||||
| import com.sk89q.worldedit.math.BlockVector3; | ||||
| @@ -37,7 +37,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; | ||||
|  * in {@link BlockArrayCacheScopedQueueCoordinator#setOffsetX(int)} and | ||||
|  * {@link BlockArrayCacheScopedQueueCoordinator#setOffsetZ(int)} | ||||
|  */ | ||||
| @AnnotationHelper.ApiDescription(info = "Internal use only. Subject to change at any time and created for specific use cases.") | ||||
| @DoNotUse | ||||
| public class BlockArrayCacheScopedQueueCoordinator extends ScopedQueueCoordinator { | ||||
|  | ||||
|     private final BlockState[][][] blockStates; | ||||
|   | ||||
| @@ -1,55 +0,0 @@ | ||||
| /* | ||||
|  * PlotSquared, a land and world management plugin for Minecraft. | ||||
|  * Copyright (C) IntellectualSites <https://intellectualsites.com> | ||||
|  * 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 <https://www.gnu.org/licenses/>. | ||||
|  */ | ||||
| package com.plotsquared.core.util; | ||||
|  | ||||
| import java.lang.annotation.Documented; | ||||
| import java.lang.annotation.Retention; | ||||
| import java.lang.annotation.RetentionPolicy; | ||||
| import java.lang.annotation.Target; | ||||
|  | ||||
| import static java.lang.annotation.ElementType.METHOD; | ||||
| import static java.lang.annotation.ElementType.MODULE; | ||||
| import static java.lang.annotation.ElementType.PACKAGE; | ||||
| import static java.lang.annotation.ElementType.RECORD_COMPONENT; | ||||
| import static java.lang.annotation.ElementType.TYPE; | ||||
|  | ||||
| /** | ||||
|  * @since 6.2.2 | ||||
|  */ | ||||
| @AnnotationHelper.ApiDescription(info = "An internal class for custom annotations." + | ||||
|         "This is in no form part of the API and is subject to change at any time.") | ||||
| public final class AnnotationHelper { | ||||
|  | ||||
|     private AnnotationHelper() { | ||||
|     } | ||||
|  | ||||
|     @Documented | ||||
|     @Retention(RetentionPolicy.CLASS) | ||||
|     @Target(value = {METHOD, PACKAGE, MODULE, RECORD_COMPONENT, TYPE}) | ||||
|     public @interface ApiDescription { | ||||
|         /** | ||||
|          * Returns additional information how to use a class for the API | ||||
|          * | ||||
|          * @return the version string | ||||
|          * @since 6.2.2 | ||||
|          */ | ||||
|         String info() default ""; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -19,6 +19,7 @@ | ||||
| package com.plotsquared.core.util; | ||||
|  | ||||
| import com.google.common.eventbus.EventBus; | ||||
| import com.intellectualsites.annotations.DoNotUse; | ||||
| import com.plotsquared.core.configuration.Settings; | ||||
| import com.plotsquared.core.configuration.caption.TranslatableCaption; | ||||
| import com.plotsquared.core.events.PlayerAutoPlotEvent; | ||||
| @@ -81,8 +82,7 @@ import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.UUID; | ||||
|  | ||||
| @AnnotationHelper.ApiDescription(info = "This is an internal class used by PlotSquared to dispatch events." + | ||||
|         "This is in no form part of the API and is subject to change at any time.") | ||||
| @DoNotUse | ||||
| public class EventDispatcher { | ||||
|  | ||||
|     private final EventBus eventBus = new EventBus("PlotSquaredEvents"); | ||||
| @@ -332,6 +332,15 @@ public class EventDispatcher { | ||||
|     ) { | ||||
|         PlotArea area = location.getPlotArea(); | ||||
|         assert area != null; | ||||
|         if (!area.buildRangeContainsY(location.getY()) && !Permissions | ||||
|                 .hasPermission(player, Permission.PERMISSION_ADMIN_BUILD_HEIGHT_LIMIT)) { | ||||
|             player.sendMessage( | ||||
|                     TranslatableCaption.of("height.height_limit"), | ||||
|                     Template.of("minHeight", String.valueOf(area.getMinBuildHeight())), | ||||
|                     Template.of("maxHeight", String.valueOf(area.getMaxBuildHeight())) | ||||
|             ); | ||||
|             return false; | ||||
|         } | ||||
|         Plot plot = area.getPlot(location); | ||||
|         if (plot != null) { | ||||
|             if (plot.isAdded(player.getUUID())) { | ||||
|   | ||||
| @@ -30,9 +30,18 @@ import org.checkerframework.checker.nullness.qual.NonNull; | ||||
|  * The Permissions class handles checking user permissions.<br> | ||||
|  * - This will respect * nodes and plots.admin and can be used to check permission ranges (e.g. plots.plot.5)<br> | ||||
|  * - Checking the PlotPlayer class directly will not take the above into account<br> | ||||
|  * | ||||
|  * @deprecated all logic that may once have been in the class lives elsewhere. We also want to do away with statically-accessed | ||||
|  * classes | ||||
|  */ | ||||
| @Deprecated(forRemoval = true, since = "6.9.3") | ||||
| public class Permissions { | ||||
|  | ||||
|     /** | ||||
|      * @deprecated all logic that may once have been in the class lives elsewhere. We also want to do away with statically-accessed | ||||
|      * classes | ||||
|      */ | ||||
|     @Deprecated(forRemoval = true, since = "6.9.3") | ||||
|     public static boolean hasPermission(PlotPlayer<?> player, Permission permission, boolean notify) { | ||||
|         return hasPermission(player, permission.toString(), notify); | ||||
|     } | ||||
| @@ -43,18 +52,25 @@ public class Permissions { | ||||
|      * @param caller     permission holder | ||||
|      * @param permission Permission | ||||
|      * @return {@code true} if the owner has the given permission, else {@code false} | ||||
|      * @deprecated all logic that may once have been in the class lives elsewhere. We also want to do away with statically-accessed | ||||
|      * classes | ||||
|      */ | ||||
|     @Deprecated(forRemoval = true, since = "6.9.3") | ||||
|     public static boolean hasPermission(final @NonNull PermissionHolder caller, final @NonNull Permission permission) { | ||||
|         return caller.hasPermission(permission.toString()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Check if the owner of the profile has a given (global) permission | ||||
|      * Check if the owner of the profile has a given (global) permission. There is no guarantee that per-world permissions will | ||||
|      * be checked because unmaintained crap plugins like PEX exist. | ||||
|      * | ||||
|      * @param caller     permission holder | ||||
|      * @param permission Permission | ||||
|      * @return {@code true} if the owner has the given permission, else {@code false} | ||||
|      * @deprecated all logic that may once have been in the class lives elsewhere. We also want to do away with statically-accessed | ||||
|      * classes | ||||
|      */ | ||||
|     @Deprecated(forRemoval = true, since = "6.9.3") | ||||
|     public static boolean hasPermission(final @NonNull PermissionHolder caller, final @NonNull String permission) { | ||||
|         return caller.hasPermission(permission); | ||||
|     } | ||||
| @@ -68,7 +84,10 @@ public class Permissions { | ||||
|      * @param key        Permission "key" | ||||
|      * @return {@code true} if the owner has the given permission, else {@code false} | ||||
|      * @since 6.0.10 | ||||
|      * @deprecated all logic that may once have been in the class lives elsewhere. We also want to do away with statically-accessed | ||||
|      * classes | ||||
|      */ | ||||
|     @Deprecated(forRemoval = true, since = "6.9.3") | ||||
|     public static boolean hasKeyedPermission( | ||||
|             final @NonNull PermissionHolder caller, final @NonNull String permission, | ||||
|             final @NonNull String key | ||||
| @@ -83,7 +102,10 @@ public class Permissions { | ||||
|      * @param permission permission | ||||
|      * @param notify     if to notify the permission holder | ||||
|      * @return if permission is had | ||||
|      * @deprecated all logic that may once have been in the class lives elsewhere. We also want to do away with statically-accessed | ||||
|      * classes | ||||
|      */ | ||||
|     @Deprecated(forRemoval = true, since = "6.9.3") | ||||
|     public static boolean hasPermission(PlotPlayer<?> player, String permission, boolean notify) { | ||||
|         if (!hasPermission(player, permission)) { | ||||
|             if (notify) { | ||||
| @@ -97,6 +119,11 @@ public class Permissions { | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @deprecated all logic that may once have been in the class lives elsewhere. We also want to do away with statically-accessed | ||||
|      * classes | ||||
|      */ | ||||
|     @Deprecated(forRemoval = true, since = "6.9.3") | ||||
|     public static int hasPermissionRange(PlotPlayer<?> player, Permission Permission, int range) { | ||||
|         return hasPermissionRange(player, Permission.toString(), range); | ||||
|     } | ||||
| @@ -110,7 +137,10 @@ public class Permissions { | ||||
|      * @param stub   The permission stub to check e.g. for `plots.plot.#` the stub is `plots.plot` | ||||
|      * @param range  The range to check | ||||
|      * @return The highest permission they have within that range | ||||
|      * @deprecated all logic that may once have been in the class lives elsewhere. We also want to do away with statically-accessed | ||||
|      * classes | ||||
|      */ | ||||
|     @Deprecated(forRemoval = true, since = "6.9.3") | ||||
|     public static int hasPermissionRange(PlotPlayer<?> player, String stub, int range) { | ||||
|         return player.hasPermissionRange(stub, range); | ||||
|     } | ||||
|   | ||||
| @@ -164,7 +164,7 @@ public final class PlaceholderRegistry { | ||||
|                     PlayerManager.getPlayerList(plot.getDenied(), player)); | ||||
|         }); | ||||
|         this.createPlaceholder("currentplot_creationdate", (player, plot) -> { | ||||
|             if (plot.getTimestamp() == 0) { | ||||
|             if (plot.getTimestamp() == 0 || !plot.hasOwner()) { | ||||
|                 return legacyComponent(TranslatableCaption.of("info.unknown"), player); | ||||
|             } | ||||
|             long creationDate = plot.getTimestamp(); | ||||
|   | ||||
| @@ -414,6 +414,7 @@ | ||||
|   "kick.you_got_kicked": "<prefix><dark_aqua>You got kicked from the plot!</dark_aqua>", | ||||
|   "trusted.trusted_added": "<prefix><dark_aqua>You successfully trusted a user to the plot.</dark_aqua>", | ||||
|   "trusted.plot_removed_user": "<prefix><red>Plot <plot> of which you were added to has been deleted due to owner inactivity.</red>", | ||||
|   "member.player_not_removed": "<prefix><gray><player></gray><red> is neither added, trusted or denied on the plot, thus doesn't need to be removed.</red>", | ||||
|   "member.removed_players": "<prefix><gray>Removed <amount> player(s) from this plot.</gray>", | ||||
|   "member.plot_left": "<prefix><gray><player> left the plot.</gray>", | ||||
|   "member.plot_cant_leave_owner": "<prefix><red>You are the plot owner. You cannot leave this plot.</red>", | ||||
| @@ -617,6 +618,7 @@ | ||||
|   "flags.flag_description_prevent_creative_copy": "<gray>Prevents people from copying item NBT data in the plot unless they're added as members.</gray>", | ||||
|   "flags.flag_description_leaf_decay": "<gray>Set to `false` to prevent leaves from decaying.", | ||||
|   "flags.flag_description_projectiles": "<gray>Prevents guests from shooting projectiles on the plot when set to false.</gray>", | ||||
|   "flags.flag_description_beacon_effect": "<gray>Enables beacon effects on the plot.</gray>", | ||||
|   "flags.flag_error_boolean": "Flag value must be a boolean (true | false).", | ||||
|   "flags.flag_error_enum": "Must be one of: <list>", | ||||
|   "flags.flag_error_integer": "Flag value must be a whole positive number.", | ||||
|   | ||||
| @@ -19,7 +19,7 @@ plugins { | ||||
| } | ||||
|  | ||||
| group = "com.plotsquared" | ||||
| version = "6.9.1-SNAPSHOT" | ||||
| version = "6.10.1-SNAPSHOT" | ||||
|  | ||||
| subprojects { | ||||
|     group = rootProject.group | ||||
| @@ -65,12 +65,12 @@ subprojects { | ||||
|     } | ||||
|  | ||||
|     dependencies { | ||||
|         implementation(platform("com.intellectualsites.bom:bom-1.18.x:1.5")) | ||||
|         implementation(platform("com.intellectualsites.bom:bom-1.18.x:1.15")) | ||||
|     } | ||||
|  | ||||
|     dependencies { | ||||
|         // Tests | ||||
|         testImplementation("org.junit.jupiter:junit-jupiter:5.8.2") | ||||
|         testImplementation("org.junit.jupiter:junit-jupiter:5.9.1") | ||||
|     } | ||||
|  | ||||
|     plugins.withId("java") { | ||||
| @@ -174,10 +174,7 @@ subprojects { | ||||
|     tasks { | ||||
|  | ||||
|         compileJava { | ||||
|             options.compilerArgs.addAll(arrayOf("-Xmaxerrs", "1000")) | ||||
|             options.compilerArgs.add("-Xlint:all") | ||||
|             for (disabledLint in arrayOf("processing", "path", "fallthrough", "serial")) | ||||
|                 options.compilerArgs.add("-Xlint:$disabledLint") | ||||
|             options.compilerArgs.add("-parameters") | ||||
|             options.isDeprecation = true | ||||
|             options.encoding = "UTF-8" | ||||
|         } | ||||
|   | ||||
| @@ -1,21 +1,20 @@ | ||||
| [versions] | ||||
| # Platform expectations | ||||
| paper = "1.18.1-R0.1-SNAPSHOT" | ||||
| checker-qual = "3.22.2" | ||||
| guice = "5.1.0" | ||||
| spotbugs = "4.7.0" | ||||
| spotbugs = "4.7.2" | ||||
|  | ||||
| # Plugins | ||||
| worldedit = "7.2.10" | ||||
| placeholderapi = "2.11.1" | ||||
| worldedit = "7.2.12" | ||||
| placeholderapi = "2.11.2" | ||||
| luckperms = "5.4" | ||||
| essentialsx = "2.19.4" | ||||
| essentialsx = "2.19.7" | ||||
| mvdwapi = "3.1.1" | ||||
|  | ||||
| # Third party | ||||
| prtree = "2.0.0" | ||||
| aopalliance = "1.0" | ||||
| cloud-services = "1.6.2" | ||||
| cloud-services = "1.7.1" | ||||
| arkitektonika = "2.1.1" | ||||
| squirrelid = "0.3.1" | ||||
| http4j = "1.3" | ||||
| @@ -29,7 +28,6 @@ nexus = "1.1.0" | ||||
| [libraries] | ||||
| # Platform expectations | ||||
| paper = { group = "io.papermc.paper", name = "paper-api", version.ref = "paper" } | ||||
| checkerqual = { group = "org.checkerframework", name = "checker-qual", version.ref = "checker-qual" } | ||||
|  | ||||
| # Platform expectations | ||||
| guice = { group = "com.google.inject", name = "guice", version.ref = "guice" } | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								gradle/wrapper/gradle-wrapper.jar
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								gradle/wrapper/gradle-wrapper.jar
									
									
									
									
										vendored
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							| @@ -1,5 +1,5 @@ | ||||
| distributionBase=GRADLE_USER_HOME | ||||
| distributionPath=wrapper/dists | ||||
| distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip | ||||
| distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip | ||||
| zipStoreBase=GRADLE_USER_HOME | ||||
| zipStorePath=wrapper/dists | ||||
|   | ||||
							
								
								
									
										6
									
								
								gradlew
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								gradlew
									
									
									
									
										vendored
									
									
								
							| @@ -205,6 +205,12 @@ set -- \ | ||||
|         org.gradle.wrapper.GradleWrapperMain \ | ||||
|         "$@" | ||||
|  | ||||
| # Stop when "xargs" is not available. | ||||
| if ! command -v xargs >/dev/null 2>&1 | ||||
| then | ||||
|     die "xargs is not available" | ||||
| fi | ||||
|  | ||||
| # Use "xargs" to parse quoted args. | ||||
| # | ||||
| # With -n1 it outputs one arg per line, with the quotes and backslashes removed. | ||||
|   | ||||
							
								
								
									
										14
									
								
								gradlew.bat
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								gradlew.bat
									
									
									
									
										vendored
									
									
								
							| @@ -14,7 +14,7 @@ | ||||
| @rem limitations under the License. | ||||
| @rem | ||||
|  | ||||
| @if "%DEBUG%" == "" @echo off | ||||
| @if "%DEBUG%"=="" @echo off | ||||
| @rem ########################################################################## | ||||
| @rem | ||||
| @rem  Gradle startup script for Windows | ||||
| @@ -25,7 +25,7 @@ | ||||
| if "%OS%"=="Windows_NT" setlocal | ||||
|  | ||||
| set DIRNAME=%~dp0 | ||||
| if "%DIRNAME%" == "" set DIRNAME=. | ||||
| if "%DIRNAME%"=="" set DIRNAME=. | ||||
| set APP_BASE_NAME=%~n0 | ||||
| set APP_HOME=%DIRNAME% | ||||
|  | ||||
| @@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome | ||||
|  | ||||
| set JAVA_EXE=java.exe | ||||
| %JAVA_EXE% -version >NUL 2>&1 | ||||
| if "%ERRORLEVEL%" == "0" goto execute | ||||
| if %ERRORLEVEL% equ 0 goto execute | ||||
|  | ||||
| echo. | ||||
| echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | ||||
| @@ -75,13 +75,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar | ||||
|  | ||||
| :end | ||||
| @rem End local scope for the variables with windows NT shell | ||||
| if "%ERRORLEVEL%"=="0" goto mainEnd | ||||
| if %ERRORLEVEL% equ 0 goto mainEnd | ||||
|  | ||||
| :fail | ||||
| rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of | ||||
| rem the _cmd.exe /c_ return code! | ||||
| if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 | ||||
| exit /b 1 | ||||
| set EXIT_CODE=%ERRORLEVEL% | ||||
| if %EXIT_CODE% equ 0 set EXIT_CODE=1 | ||||
| if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% | ||||
| exit /b %EXIT_CODE% | ||||
|  | ||||
| :mainEnd | ||||
| if "%OS%"=="Windows_NT" endlocal | ||||
|   | ||||
| @@ -1,13 +1,9 @@ | ||||
| { | ||||
|   "$schema": "https://docs.renovatebot.com/renovate-schema.json", | ||||
|   "extends": [ | ||||
|     "config:base", | ||||
|     ":disableDependencyDashboard" | ||||
|   ], | ||||
|   "timezone": "Europe/Berlin", | ||||
|   "schedule": [ | ||||
|     "every monday" | ||||
|     ":semanticCommitsDisabled" | ||||
|   ], | ||||
|   "labels": ["Renovate"], | ||||
|   "commitMessagePrefix": "build: ", | ||||
|   "rebaseWhen": "conflicted" | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user