Merge pull request #4 from true-og/agent/restrict-creative-to-worldguard-regions

Restrict creative mode to configured WorldGuard regions
This commit was merged in pull request #4.
This commit is contained in:
NotAlexNoyle authored and GitHub committed 2026-07-24 13:25:30 -04:00
commit 9913afdc1a
5 files changed
+161 -12

No files matched your search

+2
View File
@@ -39,12 +39,14 @@ repositories {
maven { url = uri("https://repo.purpurmc.org/snapshots") } // Import the PurpurMC Maven Repository.
maven("https://hub.spigotmc.org/nexus/content/groups/public/")
maven { url = uri("https://maven.playpro.com/") }
maven { url = uri("https://maven.enginehub.org/repo/") }
}
/* ---------------------- Java project deps ---------------------------- */
dependencies {
compileOnly("org.purpurmc.purpur:purpur-api:1.19.4-R0.1-SNAPSHOT") // Declare Purpur API version to be packaged.
compileOnly("net.coreprotect:coreprotect:22.4") // Import the CoreProtect API.
compileOnly("com.sk89q.worldguard:worldguard-bukkit:7.0.9") // Import the WorldGuard API.
implementation("com.zaxxer:HikariCP:5.0.1")
implementation("org.slf4j:slf4j-api:2.0.17") // Bundle a relocated SLF4J API for shaded dependencies.
implementation("org.slf4j:slf4j-nop:2.0.17") // Provide a relocated no-op SLF4J backend to avoid provider warnings.
@@ -1,11 +1,19 @@
package me.eccentric_nz.gamemodeinventories;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.regions.RegionContainer;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
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.logging.Level;
import org.bukkit.GameMode;
import org.bukkit.Location;
@@ -18,6 +26,7 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityPickupItemEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.inventory.InventoryOpenEvent;
@@ -29,11 +38,23 @@ import org.bukkit.inventory.ItemStack;
public class GameModeInventoriesListener implements Listener {
private final GameModeInventories plugin;
List<Material> containers = new ArrayList<>();
private final List<Material> containers = new ArrayList<>();
private final Set<String> creativeRegions = new HashSet<>();
private final Set<UUID> protectedFromForcedFall = new HashSet<>();
private final RegionContainer regionContainer;
public GameModeInventoriesListener(GameModeInventories plugin) {
this.plugin = plugin;
regionContainer = WorldGuard.getInstance().getPlatform().getRegionContainer();
List<String> configuredRegions = this.plugin.getConfig().getStringList("creative_regions");
if (configuredRegions.isEmpty()) {
configuredRegions = List.of("spawn");
}
configuredRegions.stream().map(region -> region.toLowerCase(Locale.ROOT)).forEach(creativeRegions::add);
for (String m : this.plugin.getConfig().getStringList("containers")) {
try {
@@ -51,11 +72,19 @@ public class GameModeInventoriesListener implements Listener {
}
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onGameModeChange(PlayerGameModeChangeEvent event) {
Player p = event.getPlayer();
GameMode newGM = event.getNewGameMode();
if (newGM.equals(GameMode.CREATIVE) && !canUseCreativeAt(p, p.getLocation())) {
event.setCancelled(true);
forceSurvival(p);
return;
}
if (newGM.equals(GameMode.SPECTATOR) && plugin.getConfig().getBoolean("restrict_spectator")
&& !p.hasPermission("gamemodeinventories.spectator") && !p.hasPermission("noclip.use"))
{
@@ -73,15 +102,11 @@ public class GameModeInventoriesListener implements Listener {
plugin.getInventoryHandler().switchInventories(p, newGM);
if (newGM.equals(GameMode.CREATIVE) && plugin.getConfig().getBoolean("creative_world.switch_to")) {
// get spawn location
Location loc = plugin.getServer().getWorld(plugin.getConfig().getString("creative_world.world"))
.getSpawnLocation();
if (plugin.getConfig().getString("creative_world.location").equals("last_known")) {
// get last known position in world
String uuid = p.getUniqueId().toString();
// player changed worlds, record last location
// check if the player has a record for this world
try (Connection connection = plugin.getDatabaseConnection();
PreparedStatement statement = connection.prepareStatement(
"SELECT * FROM " + plugin.getPrefix() + "worlds WHERE uuid = ? AND world = ?");)
@@ -101,7 +126,6 @@ public class GameModeInventoriesListener implements Listener {
double z = rs.getDouble("z");
float yaw = rs.getFloat("yaw");
float pitch = rs.getFloat("pitch");
// send to last location
loc = new Location(w, x, y, z, yaw, pitch);
}
@@ -132,6 +156,82 @@ public class GameModeInventoriesListener implements Listener {
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onMove(PlayerMoveEvent event) {
Location to = event.getTo();
if (to == null) {
return;
}
Player player = event.getPlayer();
if (protectedFromForcedFall.contains(player.getUniqueId()) && player.isOnGround()) {
protectedFromForcedFall.remove(player.getUniqueId());
}
Location from = event.getFrom();
if (player.getGameMode().equals(GameMode.CREATIVE)
&& (from.getBlockX() != to.getBlockX() || from.getBlockY() != to.getBlockY()
|| from.getBlockZ() != to.getBlockZ())
&& !canUseCreativeAt(player, to))
{
forceSurvival(player);
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onTeleportCreativeRestriction(PlayerTeleportEvent event) {
Player player = event.getPlayer();
Location to = event.getTo();
if (to != null && player.getGameMode().equals(GameMode.CREATIVE) && !canUseCreativeAt(player, to)) {
plugin.getServer().getScheduler().runTask(plugin, () -> forceSurvival(player));
}
}
@EventHandler
public void onJoin(PlayerJoinEvent event) {
Player player = event.getPlayer();
if (player.getGameMode().equals(GameMode.CREATIVE) && !canUseCreativeAt(player, player.getLocation())) {
plugin.getServer().getScheduler().runTask(plugin, () -> forceSurvival(player));
}
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onFallDamage(EntityDamageEvent event) {
if (event.getCause().equals(EntityDamageEvent.DamageCause.FALL) && event.getEntity() instanceof Player player
&& protectedFromForcedFall.remove(player.getUniqueId()))
{
event.setCancelled(true);
player.setFallDistance(0.0F);
}
}
@EventHandler
public void onQuit(PlayerQuitEvent event) {
protectedFromForcedFall.remove(event.getPlayer().getUniqueId());
}
@EventHandler(ignoreCancelled = true)
public void onInteract(PlayerInteractEvent event) {
@@ -240,8 +340,7 @@ public class GameModeInventoriesListener implements Listener {
@EventHandler(ignoreCancelled = true)
public void onPlayerInteractAtEntity(PlayerInteractAtEntityEvent event) {
// treat it the same as interacting with an entity in general
onEntityClick((PlayerInteractEntityEvent) event);
onEntityClick(event);
}
@@ -312,6 +411,43 @@ public class GameModeInventoriesListener implements Listener {
}
private boolean canUseCreativeAt(Player player, Location location) {
if (player.hasPermission("gamemodeinventories.anywhere")) {
return true;
}
ApplicableRegionSet regions = regionContainer.createQuery().getApplicableRegions(BukkitAdapter.adapt(location));
return regions.getRegions().stream()
.anyMatch(region -> creativeRegions.contains(region.getId().toLowerCase(Locale.ROOT)));
}
private void forceSurvival(Player player) {
if (!player.isOnline() || player.getGameMode().equals(GameMode.SURVIVAL)) {
return;
}
protectedFromForcedFall.add(player.getUniqueId());
player.setFallDistance(0.0F);
player.setGameMode(GameMode.SURVIVAL);
plugin.getServer().getScheduler().runTask(plugin, () -> {
if (player.isOnline() && player.isOnGround()) {
protectedFromForcedFall.remove(player.getUniqueId());
}
});
}
private boolean isBlock(Material m) {
return !m.isAir() && m.isBlock();
@@ -7,6 +7,7 @@ import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import org.bukkit.ChatColor;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
@@ -50,7 +51,12 @@ public class GameModeInventoriesMessage {
messagesConfig.getKeys(false).forEach((m) -> {
message.put(m, messagesConfig.getString(m));
String configuredMessage = messagesConfig.getString(m);
if (configuredMessage != null) {
message.put(m, ChatColor.translateAlternateColorCodes('&', configuredMessage));
}
});
@@ -94,7 +100,6 @@ public class GameModeInventoriesMessage {
out.close();
} catch (IOException e) {
}
}
@@ -112,7 +117,6 @@ public class GameModeInventoriesMessage {
in.close();
} catch (IOException e) {
}
}
@@ -134,6 +138,7 @@ public class GameModeInventoriesMessage {
if (!messagesConfig.contains(entry.getKey())) {
messagesConfig.set(entry.getKey(), entry.getValue());
message.put(entry.getKey(), ChatColor.translateAlternateColorCodes('&', entry.getValue()));
m++;
}
+2
View File
@@ -12,6 +12,8 @@ no_wither_spawn: true
no_golem_spawn: true
remove_potions: false
restrict_creative: true
creative_regions:
- spawn
containers:
- ANVIL
- BARREL
+4
View File
@@ -3,6 +3,7 @@ description: Allow players to have separate inventories for each game mode (Crea
main: me.eccentric_nz.gamemodeinventories.GameModeInventories
name: GameModeInventories-OG
load: POSTWORLD
depend: [ WorldGuard ]
softdepend: [ Multiverse-Core,MultiWorld,CoreProtect ]
version: 3.5.0
api-version: 1.19
@@ -27,6 +28,9 @@ permissions:
gamemodeinventories.toggle:
default: op
description: Allow players to toggle between CREATIVE and SURVIVAL with /gmic.
gamemodeinventories.anywhere:
default: op
description: Allow players to use CREATIVE mode outside configured WorldGuard regions.
commands:
gmi:
aliases: [ gmic ]