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