7 Commits

12 changed files with 104 additions and 211 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
target
test-server
bin
*.swp

View File

@ -4,7 +4,7 @@
<groupId>us.camin.regions</groupId>
<artifactId>Regions</artifactId>
<packaging>jar</packaging>
<version>0.2.99-rc1</version>
<version>0.2.99-rc2</version>
<name>regions</name>
<url>http://maven.apache.org</url>
<properties>
@ -16,12 +16,6 @@
<artifactId>ProtocolLib</artifactId>
<version>4.6.0</version>
</dependency>
<dependency>
<groupId>com.gmail.filoghost.holographicdisplays</groupId>
<artifactId>holographicdisplays-api</artifactId>
<version>2.4.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.papermc</groupId>
<artifactId>paperlib</artifactId>

View File

@ -131,6 +131,9 @@ public class PlayerNotifier implements Listener {
event.player.sendMessage("You discovered the region " + event.region.name());
event.player.sendTitle(title);
}
// TODO: Make this configurable and disablable
event.player.giveExp(10);
}
for(Region region : nearby) {
nearbyText.append(" ");

View File

@ -45,7 +45,6 @@ public class Plugin extends JavaPlugin {
Logger log = Logger.getLogger("Regions");
RegionManager m_regions;
PlayerWatcher m_playerWatcher;
RegionPostManager m_regionPosts;
public RegionManager regionManager() {
return m_regions;
@ -65,14 +64,6 @@ public class Plugin extends JavaPlugin {
getCommand("regions").setExecutor(new RegionsCommand(this));
getCommand("regionop").setExecutor(new RegionOpCommand(this));
boolean useHolograms = getServer().getPluginManager().isPluginEnabled("HolographicDisplays");
if (!useHolograms) {
log.info("HolographicDisplays not enabled. Region posts will not have holograms.");
}
m_regionPosts = new RegionPostManager(m_regions, this, useHolograms);
// TODO: Make holograms configurable. Disabled by default for now.
//getServer().getPluginManager().registerEvents(m_regionPosts, this);
loadRegions();
m_playerWatcher.recalculatePlayerRegions(true);
org.bukkit.plugin.Plugin mapPlugin = getServer().getPluginManager().getPlugin("dynmap");
@ -120,7 +111,6 @@ public class Plugin extends JavaPlugin {
}
public void onDisable() {
m_regionPosts.release();
saveRegions();
log.info("Plugin disabled");
}

View File

@ -42,15 +42,13 @@ public class Region {
private Location m_location;
private String m_name;
private List<Pattern> m_bannerPatterns = new ArrayList<Pattern>();
private DyeColor m_color = null;
private DyeColor m_color = DyeColor.values()[(int)(System.currentTimeMillis() % DyeColor.values().length)];
private List<UUID> m_seenPlayers = new ArrayList<UUID>();
private boolean m_isHub = false;
public Region(String name, Location location) {
m_location = location.toBlockLocation();
m_name = name;
// Pick a random color
m_color = DyeColor.values()[(int)(System.currentTimeMillis() % DyeColor.values().length)];
}
public Region(String name, Location location, int visits, int charges, DyeColor color) {
@ -61,17 +59,46 @@ public class Region {
m_color = color;
}
private static DyeColor[] defaultColors = {
DyeColor.LIGHT_BLUE,
DyeColor.BLACK,
DyeColor.BLUE,
DyeColor.CYAN,
DyeColor.BLUE,
DyeColor.GRAY,
DyeColor.GREEN,
DyeColor.PURPLE,
DyeColor.RED,
DyeColor.ORANGE,
DyeColor.GRAY,
DyeColor.GREEN,
DyeColor.MAGENTA,
DyeColor.RED,
DyeColor.WHITE,
DyeColor.YELLOW,
};
private DyeColor defaultColorForName(String name) {
int colorCount = defaultColors.length;
int hashed = Math.abs(name.hashCode());
return defaultColors[hashed % (colorCount - 1)];
}
public Region(String name, World world, RegionConfiguration conf) {
if (conf.y == -1) {
Location defaultLoc = new Location(world, conf.x, 64, conf.z);
conf.y = world.getHighestBlockAt(defaultLoc).getY();
}
Location defaultLoc = new Location(world, conf.x, 64, conf.z);
conf.y = world.getHighestBlockAt(defaultLoc).getY();
}
m_name = name;
m_visits = conf.visits;
m_charges = conf.charges;
m_location = new Location(world, conf.x, conf.y, conf.z);
m_bannerPatterns = conf.patterns;
m_color = conf.color;
if (conf.color == null) {
m_color = defaultColorForName(name);
} else {
m_color = conf.color;
}
m_seenPlayers = conf.seenBy;
m_isHub = conf.isHub;
}

View File

@ -103,7 +103,7 @@ public class RegionPostInteractionWatcher implements Listener {
player.sendMessage("You cannot use region posts at this time.");
return;
}
if (RegionPostItemWatcher.isChargeItem(handStack)) {
if (player.isSneaking() && RegionPostItemWatcher.isChargeItem(handStack) && player.hasPermission("regions.charge")) {
nearest.addCharges(1);
m_plugin.getServer().getScheduler().runTask(m_plugin, () -> {
RegionPostBuilder builder = new RegionPostBuilder(nearest, m_plugin);
@ -112,7 +112,9 @@ public class RegionPostInteractionWatcher implements Listener {
m_plugin.saveRegions();
player.setItemInHand(handStack.subtract());
m_plugin.getServer().getPluginManager().callEvent(new PlayerAddRegionChargeEvent(player, nearest));
} else if (isBannerItem(handStack)) {
// TODO: Make this configurable and disablable
player.giveExp(1);
} else if (player.isSneaking() && isBannerItem(handStack) && player.hasPermission("regions.setbanner")) {
DyeColor bannerColor = DyeColor.getByDyeData(handStack.getData().getData());
BannerMeta bannerMeta = (BannerMeta)meta;
log.info("Setting banner color to " + bannerColor);
@ -127,7 +129,7 @@ public class RegionPostInteractionWatcher implements Listener {
} else if (nearest.charges() > 0 || player.hasPermission("regions.bypass.charges")) {
m_plugin.getServer().getPluginManager().callEvent(new PlayerPostInteractEvent(player, nearest));
} else {
player.sendMessage("This region post is not charged. Right click on it while holding cobblestone.");
player.sendMessage("This region post is not charged. Right click on it while sneaking and holding a Region Post Charge.");
}
}
}

View File

@ -46,11 +46,21 @@ public class RegionPostItemWatcher implements Listener {
m_plugin = plugin;
}
static public ItemStack createCompass() {
static public ItemStack createCompass(Region r) {
ItemStack stack = new ItemStack(Material.COMPASS);
ItemMeta meta = stack.getItemMeta();
List<String> lore = new ArrayList<String>();
lore.add("Right click to locate the nearest Region Post");
if (r == null) {
lore.add("Right click to locate the nearest Region Post");
} else {
CompassMeta compassMeta = (CompassMeta)meta;
compassMeta.setDisplayName(r.name() + " Region Compass");
compassMeta.setLodestone(r.location());
compassMeta.setLodestoneTracked(false);
lore.add("Right click to locate the nearest Region Post");
lore.add("Tracking: " + r.name());
lore.add("Coordinates: " + r.location().getX() + ", " + r.location().getY());
}
meta.setLore(lore);
meta.addEnchant(Enchantment.SOUL_SPEED, 1, true);
meta.addItemFlags(ItemFlag.HIDE_ENCHANTS);
@ -71,7 +81,7 @@ public class RegionPostItemWatcher implements Listener {
return stack;
}
static public ItemStack createCreateItem() {
static public ItemStack createAnchor() {
ItemStack stack = new ItemStack(Material.LANTERN);
ItemMeta meta = stack.getItemMeta();
List<String> lore = new ArrayList<String>();
@ -79,12 +89,13 @@ public class RegionPostItemWatcher implements Listener {
meta.addItemFlags(ItemFlag.HIDE_ENCHANTS);
meta.addEnchant(Enchantment.SOUL_SPEED, 1, true);
meta.setLore(lore);
meta.setDisplayName("Region Post Anchor");
stack.setItemMeta(meta);
return stack;
}
private ItemStack m_theCompass = createCompass();
private ItemStack m_theItem = createCreateItem();
private ItemStack m_theCompass = createCompass(null);
private ItemStack m_theAnchor = createAnchor();
private static ItemStack m_theChargeItem = createChargeItem();
public static boolean isChargeItem(ItemStack stack) {
@ -96,9 +107,9 @@ public class RegionPostItemWatcher implements Listener {
return true;
}
if (stack.getType() == m_theItem.getType()) {
if (stack.getType() == m_theCompass.getType()) {
ItemMeta meta = stack.getItemMeta();
ItemMeta theItemMeta = m_theItem.getItemMeta();
ItemMeta theItemMeta = m_theCompass.getItemMeta();
if (meta.getItemFlags() == theItemMeta.getItemFlags()) {
return true;
}
@ -108,14 +119,14 @@ public class RegionPostItemWatcher implements Listener {
}
public boolean isRegionCreateItem(ItemStack stack, Player p) {
if (stack.isSimilar(m_theItem)) {
if (stack.isSimilar(m_theAnchor)) {
return true;
}
if (stack.getType() == m_theItem.getType()) {
if (stack.getType() == m_theAnchor.getType()) {
ItemMeta meta = stack.getItemMeta();
ItemMeta theItemMeta = m_theItem.getItemMeta();
if (meta.getLore().equals(theItemMeta.getLore())) {
ItemMeta theItemMeta = m_theAnchor.getItemMeta();
if (meta.getLore() != null && meta.getLore().equals(theItemMeta.getLore())) {
return true;
}
}
@ -134,35 +145,26 @@ public class RegionPostItemWatcher implements Listener {
if (isRegionCompass(handStack) && event.getAction() == Action.RIGHT_CLICK_AIR) {
event.setCancelled(true);
ItemStack compassItem = new ItemStack(Material.COMPASS);
Region nearest = m_manager.nearestRegion(player.getLocation());
if (nearest == null) {
player.sendMessage("There are no regions in this world!");
return;
}
CompassMeta compassMeta = (CompassMeta)compassItem.getItemMeta();
compassMeta.setDisplayName(nearest.name());
compassMeta.setLodestone(nearest.location());
compassMeta.setLodestoneTracked(false);
ArrayList<String> newLore = new ArrayList<String>();
newLore.add("Right click to locate the nearest Region Post");
newLore.add("Tracking: " + nearest.name());
compassMeta.setLore(newLore);
compassItem.setItemMeta(compassMeta);
ItemStack compassItem = createCompass(nearest);
player.setItemInHand(compassItem);
player.sendMessage("Now tracking " + nearest.name());
} else if (!event.isCancelled() && isRegionCreateItem(handStack, player) && event.getAction() == Action.RIGHT_CLICK_BLOCK && !event.getClickedBlock().getType().isInteractable()) {
} else if (!event.isCancelled() && isRegionCreateItem(handStack, player) && event.getAction() == Action.RIGHT_CLICK_BLOCK && !event.getClickedBlock().getType().isInteractable() && player.hasPermission("regions.create")) {
event.setUseItemInHand(Event.Result.DENY);
event.setCancelled(true);
if (meta.getDisplayName().equals("")) {
if (meta.getDisplayName().equals("") || meta.getDisplayName().equals("Region Post Anchor")) {
player.sendMessage("You must first give this item a name!");
} else {
Region nearest = m_manager.nearestRegion(player.getLocation());
if (nearest != null && player.getLocation().distance(nearest.interactLocation()) <= 500) {
player.sendMessage("You are too close to the region post for " + nearest.name());
Region nearest = m_manager.nearestRegion(event.getClickedBlock().getLocation());
if (nearest != null && event.getClickedBlock().getLocation().distance(nearest.interactLocation()) < 500) {
int distance = 500 - (int)event.getClickedBlock().getLocation().distance(nearest.interactLocation());
player.sendMessage("You are " + distance + " blocks too close to the region post for " + nearest.name() + ".");
} else {
Region r = new Region(meta.getDisplayName(), event.getClickedBlock().getRelative(event.getBlockFace()).getLocation());
//player.teleport(r.teleportLocation());
m_plugin.getServer().getScheduler().runTask(m_plugin, () -> {
RegionPostBuilder builder = new RegionPostBuilder(r, m_plugin);
builder.build();

View File

@ -1,141 +0,0 @@
package us.camin.regions;
/**
* This file is part of Regions
*
* Regions 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.
*
* Regions 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 Regions. If not, see <http://www.gnu.org/licenses/>.
*
*/
import org.bukkit.event.Listener;
import org.bukkit.event.EventHandler;
import org.bukkit.Location;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.logging.Logger;
import com.gmail.filoghost.holographicdisplays.api.HologramsAPI;
import us.camin.regions.events.PlayerNearRegionPostEvent;
import us.camin.regions.events.RegionCreateEvent;
import us.camin.regions.events.RegionRemoveEvent;
import us.camin.regions.ui.RegionPostBuilder;
import com.gmail.filoghost.holographicdisplays.api.Hologram;
public class RegionPostManager implements Listener {
Logger log = Logger.getLogger("Regions.RegionPostManager");
Plugin m_plugin;
RegionManager m_regions;
boolean m_useHolograms;
HashMap<Region, Hologram> m_regionHolograms;
//HashMap<Region, ArmorStand> m_armorStands;
public RegionPostManager(RegionManager regions, Plugin plugin, boolean useHolograms) {
//m_armorStands = new HashMap<Region, ArmorStand>();
m_regions = regions;
m_plugin = plugin;
m_useHolograms = useHolograms;
m_regionHolograms = new HashMap<>();
}
@EventHandler
public void onRegionCreate(RegionCreateEvent event) {
Location loc = event.region.location();
if (loc.getWorld().isChunkLoaded((int)loc.getX(), (int)loc.getY())) {
createHologram(event.region);
queueRebuild(event.region);
}
}
@EventHandler
public void onPlayerNearRegionPost(PlayerNearRegionPostEvent event) {
createHologram(event.region);
}
private void queueRebuild(Region region) {
if (region != null) {
log.info("Rebuilding region post for " + region.name());
m_plugin.getServer().getScheduler().runTask(m_plugin, () -> {
RegionPostBuilder builder = new RegionPostBuilder(region, m_plugin);
builder.build();
});
}
}
@EventHandler
public void onRegionDestroy(RegionRemoveEvent event) {
destroyHologram(event.region);
}
public void release() {
for(Region r : new ArrayList<>(m_regionHolograms.keySet())) {
destroyHologram(r);
}
/*for(Region r : new ArrayList<>(m_armorStands.keySet())) {
destroyHologram(r);
}*/
}
private void createHologram(Region r) {
if (!m_useHolograms) {
return;
}
Hologram hologram = m_regionHolograms.get(r);
if (hologram == null) {
hologram = HologramsAPI.createHologram(m_plugin, r.teleportLocation().clone().add(0.5, 0, 0.5));
hologram.appendTextLine(r.coloredName());
m_regionHolograms.put(r, hologram);
}
/*boolean needsRegen = false;
if (m_armorStands.containsKey(r)) {
// If we have an armor stand, but it isn't valid, regen
needsRegen = !m_armorStands.get(r).isValid();
} else {
// If we don't have an armor stand at all, regen
needsRegen = true;
}
if (needsRegen) {
log.info("Creating hologram for " + r.name());
Location markerLocation = r.teleportLocation().clone().add(0.5, 0, 0.5);
ArmorStand stand = (ArmorStand) r.location().getWorld().spawnEntity(markerLocation, EntityType.ARMOR_STAND);
stand.setVisible(false);
stand.setCustomName(r.coloredName());
stand.setMarker(true);
stand.setSmall(true);
stand.setRemoveWhenFarAway(true);
stand.setCustomNameVisible(true);
stand.setInvulnerable(true);
stand.setSilent(true);
m_armorStands.put(r, stand);
}*/
}
private void destroyHologram(Region r) {
if (!m_useHolograms) {
return;
}
Hologram hologram = m_regionHolograms.get(r);
if (hologram != null) {
hologram.delete();
}
/*log.info("Destroying hologram for " + r.name());
ArmorStand stand = m_armorStands.get(r);
if (stand != null && stand.isValid()) {
stand.remove();
}
m_armorStands.remove(r);*/
}
}

View File

@ -70,7 +70,7 @@ public class RegionCommand implements CommandExecutor, TabCompleter {
return true;
}
String subCommand = split[0];
if (subCommand.equals("create") && p.hasPermission("regions.create")) {
if (subCommand.equals("create") && p.hasPermission("regions.commands.create")) {
if (split.length <= 1) {
p.sendMessage("Must specify a region name");
return true;
@ -85,7 +85,7 @@ public class RegionCommand implements CommandExecutor, TabCompleter {
p.teleport(r.teleportLocation());
m_plugin.regionManager().addRegion(r);
m_plugin.saveRegions();
} else if (subCommand.equals("remove") && p.hasPermission("regions.remove")) {
} else if (subCommand.equals("remove") && p.hasPermission("regions.commands.remove")) {
Region r = m_plugin.regionManager().nearestRegion(p.getLocation());
if (r == null) {
p.sendMessage("There are no regions in this world.");
@ -94,7 +94,7 @@ public class RegionCommand implements CommandExecutor, TabCompleter {
m_plugin.regionManager().removeRegion(r);
p.sendMessage("Deleted region " + r.coloredName());
m_plugin.saveRegions();
} else if (subCommand.equals("regen") && p.hasPermission("regions.regen")) {
} else if (subCommand.equals("regen") && p.hasPermission("regions.commands.regen")) {
Region r = m_plugin.regionManager().nearestRegion(p.getLocation());
if (r == null) {
p.sendMessage("There are no regions in this world.");
@ -106,7 +106,7 @@ public class RegionCommand implements CommandExecutor, TabCompleter {
p.sendMessage("Region post regenerated.");
});
}
} else if (subCommand.equals("regenall") && p.hasPermission("regions.regen.all")) {
} else if (subCommand.equals("regenall") && p.hasPermission("regions.commands.regen.all")) {
for(Region r : m_plugin.regionManager().regionsForWorld(p.getLocation().getWorld())) {
m_plugin.getServer().getScheduler().runTask(m_plugin, () -> {
RegionPostBuilder builder = new RegionPostBuilder(r, m_plugin);

View File

@ -62,7 +62,7 @@ public class RegionOpCommand implements CommandExecutor, TabCompleter {
});
} else if (subCommand.equals("compass") && sender.hasPermission("regions.give-items.compass")) {
Player player = (Player)sender;
ItemStack compassItem = RegionPostItemWatcher.createCreateItem();
ItemStack compassItem = RegionPostItemWatcher.createCompass(m_plugin.regionManager().nearestRegion(player.getLocation()));
if (split.length > 1) {
compassItem.setAmount(Integer.parseInt(split[1]));
}
@ -72,11 +72,11 @@ public class RegionOpCommand implements CommandExecutor, TabCompleter {
}
} else if (subCommand.equals("item") && sender.hasPermission("regions.give-items.creator")) {
Player player = (Player)sender;
ItemStack createItem = RegionPostItemWatcher.createCreateItem();
ItemStack anchorStack = RegionPostItemWatcher.createAnchor();
if (split.length > 1) {
createItem.setAmount(Integer.parseInt(split[1]));
anchorStack.setAmount(Integer.parseInt(split[1]));
}
HashMap<Integer, ItemStack> rejected = player.getInventory().addItem(createItem);
HashMap<Integer, ItemStack> rejected = player.getInventory().addItem(anchorStack);
for(ItemStack item : rejected.values()) {
player.getLocation().getWorld().dropItem(player.getLocation(), item);
}

View File

@ -16,7 +16,7 @@ import us.camin.regions.Region;
import java.util.UUID;
public class RegionConfiguration implements ConfigurationSerializable {
public int x;
public int x;
public int y;
public int z;
public int visits;
@ -24,7 +24,7 @@ public class RegionConfiguration implements ConfigurationSerializable {
public boolean isHub;
public List<Pattern> patterns;
public List<UUID> seenBy;
public DyeColor color = DyeColor.YELLOW;
public DyeColor color = null;
public RegionConfiguration(Region region) {
Location loc = region.location();
@ -47,7 +47,10 @@ public class RegionConfiguration implements ConfigurationSerializable {
visits = (Integer)confSection.getOrDefault("visits", 0);
charges = (Integer)confSection.getOrDefault("charges", 0);
patterns = (List<Pattern>)confSection.getOrDefault("banner", new ArrayList<Pattern>());
color = DyeColor.valueOf((String)confSection.getOrDefault("color", "YELLOW"));
String colorStr = (String)confSection.getOrDefault("color", null);
if (colorStr != null) {
color = DyeColor.valueOf(colorStr);
}
seenBy = new ArrayList<UUID>();
List<String> strList = (List<String>)confSection.getOrDefault("seenBy", new ArrayList<String>());
for(String s : strList) {

View File

@ -21,7 +21,7 @@ permissions:
description: Allows use of all regions permissions
children:
regions.create: true
regions.remove: true
regions.commands.*: true
regions.regen.*: true
regions.bypass.*: true
regions.give-items.*: true
@ -35,15 +35,27 @@ permissions:
default: true
description: Use region posts
regions.create:
default: true
description: Create a region with a region item
regions.setbanner:
default: true
description: Allows setting a region post banner
regions.charge:
default: true
description: Allows charging a region post with a charge item
regions.commands.*:
default: op
description: Create a region
regions.remove:
children:
regions.commands.remove: true
regions.commands.regen: true
regions.commands.regen.all: true
regions.commands.remove:
default: op
description: Remove a region
regions.regen:
regions.commands.regen:
default: op
description: Regenerates a region post
regions.regen.all:
regions.commands.regen.all:
default: op
description: Regenerates all region posts, including in unloaded chunks
regions.bypass.*: