diff --git a/README.md b/README.md index 3bcdb6f..5c3f326 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,10 @@ SRegionProtector is a nukkit plugin that allows players to protect their regions. ## Download * [NukkitX.com](https://nukkitx.com/resources/sregionprotector.164/) -* [GoogleDrive](https://drive.google.com/file/d/1eCtg4VsgBcNEMaApQJRn5yW5YP_fAUd9/view?usp=sharing) +* [GoogleDrive](https://drive.google.com/file/d/1aQJ1U2J_toxUKHs266ikN0MJE8jTwcOq/view?usp=sharing) * [All versions](https://drive.google.com/drive/folders/1Z98RAPGY-7NK49ktsBYkZgafUB50r7NC?usp=sharing) ## Features +* GUI * API for another plugins * Lots of flags * Flexible settings diff --git a/pom.xml b/pom.xml index e1b03b4..4b7e4df 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ sergeydertan.sregionprotector SRegionProtector - 19.2 + 19.3 SRegionProtector Flexible region protection plugin for nukkit https://github.com/SergeyDertan/SRegionProtector diff --git a/src/main/java/Sergey_Dertan/SRegionProtector/Event/RegionEventsHandler.java b/src/main/java/Sergey_Dertan/SRegionProtector/Event/RegionEventsHandler.java index 96203b2..8d5d1b4 100644 --- a/src/main/java/Sergey_Dertan/SRegionProtector/Event/RegionEventsHandler.java +++ b/src/main/java/Sergey_Dertan/SRegionProtector/Event/RegionEventsHandler.java @@ -5,6 +5,7 @@ import Sergey_Dertan.SRegionProtector.Region.Chunk.ChunkManager; import Sergey_Dertan.SRegionProtector.Region.Flags.RegionFlags; import Sergey_Dertan.SRegionProtector.Region.Region; +import Sergey_Dertan.SRegionProtector.Utils.Pair; import Sergey_Dertan.SRegionProtector.Utils.Tags; import cn.nukkit.Player; import cn.nukkit.block.*; @@ -27,15 +28,16 @@ import cn.nukkit.event.redstone.RedstoneUpdateEvent; import cn.nukkit.event.weather.LightningStrikeEvent; import cn.nukkit.item.ItemID; +import cn.nukkit.level.EnumLevel; import cn.nukkit.level.Position; import cn.nukkit.level.Sound; +import cn.nukkit.level.format.FullChunk; import cn.nukkit.math.BlockFace; import cn.nukkit.math.Vector3; import it.unimi.dsi.fastutil.objects.Object2BooleanArrayMap; import it.unimi.dsi.fastutil.objects.Object2BooleanMap; -import java.util.Collection; -import java.util.Iterator; +import java.util.*; @SuppressWarnings({"WeakerAccess", "unused"}) public final class RegionEventsHandler implements Listener { @@ -50,6 +52,9 @@ public final class RegionEventsHandler implements Listener { private final Object2BooleanMap isMonster; private final Class monster; //mobplugin + private final Pair[] portalBlocks; + + @SuppressWarnings("unchecked") public RegionEventsHandler(ChunkManager chunkManager, boolean[] flagsStatus, boolean[] needMessage, boolean prioritySystem) { this.chunkManager = chunkManager; this.flagsStatus = flagsStatus; @@ -64,6 +69,60 @@ public RegionEventsHandler(ChunkManager chunkManager, boolean[] flagsStatus, boo } catch (ClassNotFoundException ignore) { } this.monster = monster; + + this.portalBlocks = this.netherPortalBlocks(); + } + + /** + * @see BlockNetherPortal#spawnPortal(Position) + */ + private Pair[] netherPortalBlocks() { + Map blocks = new HashMap<>(); + + blocks.put(new Vector3(1), BlockID.OBSIDIAN); + blocks.put(new Vector3(2), BlockID.OBSIDIAN); + + //z=1 + blocks.put(new Vector3(0, 0, 1), BlockID.OBSIDIAN); + blocks.put(new Vector3(1, 0, 1), BlockID.OBSIDIAN); + blocks.put(new Vector3(2, 0, 1), BlockID.OBSIDIAN); + blocks.put(new Vector3(3, 0, 1), BlockID.OBSIDIAN); + //z=2 + blocks.put(new Vector3(1, 0, 2), BlockID.OBSIDIAN); + blocks.put(new Vector3(2, 0, 2), BlockID.OBSIDIAN); + //z=1 + //y=1 + blocks.put(new Vector3(0, 1, 1), BlockID.OBSIDIAN); + blocks.put(new Vector3(1, 1, 1), BlockID.NETHER_PORTAL); + blocks.put(new Vector3(2, 1, 1), BlockID.NETHER_PORTAL); + blocks.put(new Vector3(3, 1, 1), BlockID.OBSIDIAN); + //y=2 + //z=1 + blocks.put(new Vector3(0, 2, 1), BlockID.OBSIDIAN); + blocks.put(new Vector3(1, 2, 1), BlockID.NETHER_PORTAL); + blocks.put(new Vector3(2, 2, 1), BlockID.NETHER_PORTAL); + blocks.put(new Vector3(3, 2, 1), BlockID.OBSIDIAN); + //y=3 + blocks.put(new Vector3(0, 3, 1), BlockID.OBSIDIAN); + blocks.put(new Vector3(1, 3, 1), BlockID.NETHER_PORTAL); + blocks.put(new Vector3(2, 3, 1), BlockID.NETHER_PORTAL); + blocks.put(new Vector3(3, 3, 1), BlockID.OBSIDIAN); + //y=4 + blocks.put(new Vector3(0, 4, 1), BlockID.OBSIDIAN); + blocks.put(new Vector3(1, 4, 1), BlockID.OBSIDIAN); + blocks.put(new Vector3(2, 4, 1), BlockID.OBSIDIAN); + blocks.put(new Vector3(3, 4, 1), BlockID.OBSIDIAN); + + for (int x = -1; x < 4; x++) { + for (int y = 1; y < 4; y++) { + for (int z = -1; z < 3; z++) { + blocks.putIfAbsent(new Vector3(x, y, z), BlockID.AIR); + } + } + } + List> blockss = new ArrayList<>(); + blocks.forEach((k, v) -> blockss.add(new Pair<>(k, v))); + return blockss.toArray(new Pair[0]); } //break & minefarm flags @@ -355,6 +414,40 @@ public void levelLoad(LevelLoadEvent e) { } } + //prevent nether portal from spawning in region + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + public void entityPortalEnter(EntityPortalEnterEvent e) { + if (!this.flagsStatus[RegionFlags.FLAG_NETHER_PORTAL]) return; + if (e.getPortalType() != EntityPortalEnterEvent.PortalType.NETHER) return; + Position portal = EnumLevel.moveToNether(e.getEntity()).floor(); + if (portal == null) return; + + for (int x = -1; x < 2; x++) { + for (int z = -1; z < 2; z++) { + int chunkX = (portal.getFloorX() >> 4) + x; + int chunkZ = (portal.getFloorZ() >> 4) + z; + FullChunk chunk = portal.level.getChunk(chunkX, chunkZ, true); + if (chunk == null || !(chunk.isGenerated() || chunk.isPopulated())) { + portal.level.generateChunk(chunkX, chunkZ, true); + } + } + } + + for (Pair block : this.portalBlocks) { + Vector3 pos = portal.add(block.key).floor(); + if (portal.level.getBlockIdAt((int) pos.x, (int) pos.y, (int) pos.z) != block.value) { + Region region = this.chunkManager.getRegion(pos, portal.level.getName()); + if (region != null && region.getFlagState(RegionFlags.FLAG_NETHER_PORTAL)) { + e.setCancelled(); + if (e.getEntity() instanceof Player) { + Messenger.getInstance().sendMessage(((Player) e.getEntity()), "region.protected." + RegionFlags.getFlagName(RegionFlags.FLAG_NETHER_PORTAL)); + } + break; + } + } + } + } + private boolean canInteractWith(int flag, Position pos, Player player) { if (!this.flagsStatus[flag]) return false; Chunk chunk = this.chunkManager.getChunk((long) pos.x, (long) pos.z, pos.level.getName(), true, false); diff --git a/src/main/java/Sergey_Dertan/SRegionProtector/GUI/Page/FlagsPage.java b/src/main/java/Sergey_Dertan/SRegionProtector/GUI/Page/FlagsPage.java index 34b83ab..63743ea 100644 --- a/src/main/java/Sergey_Dertan/SRegionProtector/GUI/Page/FlagsPage.java +++ b/src/main/java/Sergey_Dertan/SRegionProtector/GUI/Page/FlagsPage.java @@ -49,6 +49,8 @@ public final class FlagsPage implements Page { this.flagToBlock[RegionFlags.FLAG_MINEFARM] = BlockID.DIAMOND_ORE; this.flagToBlock[RegionFlags.FLAG_POTION_LAUNCH] = ItemID.SPLASH_POTION; this.flagToBlock[RegionFlags.FLAG_HEAL] = ItemID.GOLDEN_APPLE; + this.flagToBlock[RegionFlags.FLAG_NETHER_PORTAL] = BlockID.NETHER_PORTAL; + this.flagToBlock[RegionFlags.FLAG_SELL] = ItemID.EMERALD; } @Override diff --git a/src/main/java/Sergey_Dertan/SRegionProtector/Provider/DataObject/Converter.java b/src/main/java/Sergey_Dertan/SRegionProtector/Provider/DataObject/Converter.java index d0402c6..0df507f 100644 --- a/src/main/java/Sergey_Dertan/SRegionProtector/Provider/DataObject/Converter.java +++ b/src/main/java/Sergey_Dertan/SRegionProtector/Provider/DataObject/Converter.java @@ -3,15 +3,12 @@ import Sergey_Dertan.SRegionProtector.Region.Flags.Flag.RegionFlag; import Sergey_Dertan.SRegionProtector.Region.Flags.Flag.RegionSellFlag; import Sergey_Dertan.SRegionProtector.Region.Flags.Flag.RegionTeleportFlag; -import Sergey_Dertan.SRegionProtector.Region.Flags.RegionFlags; import Sergey_Dertan.SRegionProtector.Region.Region; import Sergey_Dertan.SRegionProtector.Utils.Utils; import cn.nukkit.math.Vector3; import com.alibaba.fastjson.JSON; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; +import java.util.*; import static Sergey_Dertan.SRegionProtector.Region.Flags.RegionFlags.*; import static Sergey_Dertan.SRegionProtector.Utils.Tags.*; @@ -95,11 +92,11 @@ public static Region fromDataObject(RegionDataObject dataObject, RegionFlag[] fl } public static Region fromDataObject(RegionDataObject dataObject, FlagListDataObject flagsDataObject) { - return fromDataObject(dataObject, fromDataObject(flagsDataObject)); + return fromDataObject(dataObject, fromDataObject(flagsDataObject).toArray(new RegionFlag[0])); } - public static RegionFlag[] fromDataObject(FlagListDataObject dataObject) { - RegionFlag[] flags = new RegionFlag[RegionFlags.FLAG_AMOUNT]; + public static List fromDataObject(FlagListDataObject dataObject) { + List flags = new ArrayList<>(); Boolean[] state = JSON.parseArray(dataObject.state, Boolean.class).toArray(new Boolean[0]); @SuppressWarnings("unchecked") Map teleportData = (Map) JSON.parse(dataObject.teleportData); @@ -109,24 +106,24 @@ public static RegionFlag[] fromDataObject(FlagListDataObject dataObject) { double y = ((Number) teleportData.get(Y_TAG)).doubleValue(); double z = ((Number) teleportData.get(Z_TAG)).doubleValue(); String level = (String) teleportData.get(LEVEL_TAG); - flags[i] = new RegionTeleportFlag(state[i], new Vector3(x, y, z), level); + flags.add(new RegionTeleportFlag(state[i], new Vector3(x, y, z), level)); continue; } if (i == FLAG_SELL) { - flags[i] = new RegionSellFlag(state[i], dataObject.sellData); + flags.add(new RegionSellFlag(state[i], dataObject.sellData)); continue; } - flags[i] = new RegionFlag(state[i]); + flags.add(new RegionFlag(state[i])); } return flags; } public static FlagListDataObject toDataObject(Map> data) { //for the yaml data provider FlagListDataObject dataObject = new FlagListDataObject(); - boolean[] state = new boolean[RegionFlags.FLAG_AMOUNT]; + List state = new ArrayList<>(); for (Map.Entry> flag : data.entrySet()) { if (getFlagId(flag.getKey()) == FLAG_INVALID) continue; - state[getFlagId(flag.getKey())] = (Boolean) flag.getValue().get(STATE_TAG); + state.add(getFlagId(flag.getKey()), (Boolean) flag.getValue().get(STATE_TAG)); if (getFlagId(flag.getKey()) == FLAG_SELL) { dataObject.sellData = ((Number) flag.getValue().getOrDefault(PRICE_TAG, -1L)).longValue(); } @@ -141,7 +138,7 @@ public static FlagListDataObject toDataObject(Map> d dataObject.teleportData = JSON.toJSONString(teleport); } } - dataObject.state = JSON.toJSONString(state); + dataObject.state = JSON.toJSONString(state.toArray(new Boolean[0])); return dataObject; } } diff --git a/src/main/java/Sergey_Dertan/SRegionProtector/Region/Flags/RegionFlags.java b/src/main/java/Sergey_Dertan/SRegionProtector/Region/Flags/RegionFlags.java index 90bd06a..683de96 100644 --- a/src/main/java/Sergey_Dertan/SRegionProtector/Region/Flags/RegionFlags.java +++ b/src/main/java/Sergey_Dertan/SRegionProtector/Region/Flags/RegionFlags.java @@ -14,6 +14,7 @@ import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; @SuppressWarnings({"WeakerAccess", "unused"}) @@ -57,8 +58,9 @@ public abstract class RegionFlags { public static final int FLAG_SMART_DOORS = 31; public static final int FLAG_MINEFARM = 32; public static final int FLAG_FALL_DAMAGE = 33; + public static final int FLAG_NETHER_PORTAL = 34; - public static final int FLAG_AMOUNT = 34; + public static final int FLAG_AMOUNT = 35; public static final RegionFlag[] defaults = new RegionFlag[FLAG_AMOUNT]; public static final Permission[] permissions = new Permission[FLAG_AMOUNT]; @@ -103,6 +105,7 @@ public abstract class RegionFlags { flagList.put(FLAG_SMART_DOORS, "smart-doors"); flagList.put(FLAG_MINEFARM, "minefarm"); flagList.put(FLAG_FALL_DAMAGE, "fall-damage"); + flagList.put(FLAG_NETHER_PORTAL, "nether-portal"); flags = ImmutableBiMap.copyOf(flagList); Map aAliases = new HashMap<>(FLAG_AMOUNT); @@ -150,6 +153,7 @@ public abstract class RegionFlags { fState.put(FLAG_SMART_DOORS, false); fState.put(FLAG_MINEFARM, false); fState.put(FLAG_FALL_DAMAGE, false); + fState.put(FLAG_NETHER_PORTAL, true); state = ImmutableMap.copyOf(fState); } @@ -190,10 +194,9 @@ public static boolean getStateFromString(String state, int flag) { throw new RuntimeException("Wrong state"); } - public static void fixMissingFlags(RegionFlag[] flags) { - for (int i = 0; i < FLAG_AMOUNT; ++i) { - if (flags[i] != null) continue; - flags[i] = defaults[i].clone(); + public static void fixMissingFlags(List flags) { + for (int i = flags.size(); i < FLAG_AMOUNT; ++i) { + flags.add(defaults[i].clone()); } } diff --git a/src/main/java/Sergey_Dertan/SRegionProtector/Region/RegionManager.java b/src/main/java/Sergey_Dertan/SRegionProtector/Region/RegionManager.java index 1665a9f..3777f44 100644 --- a/src/main/java/Sergey_Dertan/SRegionProtector/Region/RegionManager.java +++ b/src/main/java/Sergey_Dertan/SRegionProtector/Region/RegionManager.java @@ -93,15 +93,15 @@ public void init() { FlagListDataObject flags = this.provider.loadFlags(name); - RegionFlag[] flagList = Converter.fromDataObject(flags); + List flagList = Converter.fromDataObject(flags); boolean needUpdate = false; - if (flagList.length < FLAG_AMOUNT) { + if (flagList.size() < FLAG_AMOUNT) { needUpdate = true; fixMissingFlags(flagList); } - Region region = new Region(name, creator, level, priority, minX, minY, minZ, maxX, maxY, maxZ, owners, members, flagList); + Region region = new Region(name, creator, level, priority, minX, minY, minZ, maxX, maxY, maxZ, owners, members, flagList.toArray(new RegionFlag[0])); region.needUpdate = needUpdate; diff --git a/src/main/java/Sergey_Dertan/SRegionProtector/Utils/Pair.java b/src/main/java/Sergey_Dertan/SRegionProtector/Utils/Pair.java index a782592..618b26e 100644 --- a/src/main/java/Sergey_Dertan/SRegionProtector/Utils/Pair.java +++ b/src/main/java/Sergey_Dertan/SRegionProtector/Utils/Pair.java @@ -1,5 +1,7 @@ package Sergey_Dertan.SRegionProtector.Utils; +import java.util.Objects; + public final class Pair { public F key; @@ -9,4 +11,19 @@ public Pair(F key, S value) { this.key = key; this.value = value; } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj instanceof Pair) { + Pair pair = (Pair) obj; + return Objects.equals(this.key, pair.key) && Objects.equals(this.value, pair.value); + } + return false; + } + + @Override + public int hashCode() { + return (this.key != null ? this.key.hashCode() : 0) * 13 + (this.value != null ? this.value.hashCode() : 0); + } } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index a388458..8fbdbc6 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -57,6 +57,7 @@ active-flags: smart-doors: true minefarm: true fall-damage: true + nether-portal: true display: place: true break: true diff --git a/src/main/resources/lang/eng.yml b/src/main/resources/lang/eng.yml index 7184cd6..d58a9c8 100644 --- a/src/main/resources/lang/eng.yml +++ b/src/main/resources/lang/eng.yml @@ -53,7 +53,8 @@ region.protected.ender-pearl: "You can`t use enderpearl in this region" region.protected.chest-access: "You can`t use chests in this region" region.protected.sleep: "You can`t use bed in this region" region.protected.fire: "You can`t ignite blocks in this region" -region.protected.fall_damage: "You can`t take fall damage in this region" +region.protected.fall-damage: "You can`t take fall damage in this region" +region.protected.nether-portal: "Nether portal can`t be created in region" region.selection.pos1: "First pos set" region.selection.pos2: "Second pos set" diff --git a/src/main/resources/lang/rus.yml b/src/main/resources/lang/rus.yml index a1b2b37..803f378 100644 --- a/src/main/resources/lang/rus.yml +++ b/src/main/resources/lang/rus.yml @@ -53,7 +53,8 @@ region.protected.ender-pearl: "Вы не можете использовать region.protected.chest-access: "Вы не можете использовать сундуки в этом регионе" region.protected.sleep: "Вы не можете использовать кровать в этом регионе" region.protected.fire: "Вы не можете поджигать в этом регионе" -region.protected.fall_damage: "Вы не можете получать урон от падения в этом регионе" +region.protected.fall-damage: "Вы не можете получать урон от падения в этом регионе" +region.protected.nether-portal: "Портал не может быть создан в этом регионе" region.selection.pos1: "Первая точка установлена" region.selection.pos2: "Вторая точка установлена" diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 5ed09c7..26d03fa 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -161,8 +161,10 @@ permissions: sregionprotector.region.flag.chunk_loader: default: op sregionprotector.region.flag.smart_doors: - default: op + default: true sregionprotector.region.flag.minefarm: default: op sregionprotector.region.flag.fall_damage: default: op + sregionprotector.region.flag.nether_portal: + default: op diff --git a/src/main/resources/region-settings.yml b/src/main/resources/region-settings.yml index 2f40eeb..803d7ae 100644 --- a/src/main/resources/region-settings.yml +++ b/src/main/resources/region-settings.yml @@ -32,6 +32,7 @@ default-flags: smart-doors: true minefarm: false fall-damage: false + nether-portal: true need-message: move: false place: true @@ -55,6 +56,7 @@ need-message: sleep: true minefarm: false fall-damage: false + nether-portal: true max-region-name-length: 10 min-region-name-length: 3 # 1 second = 20 ticks