parent
c6fd4b2604
commit
989b2bb07c
|
@ -0,0 +1,51 @@
|
|||
package com.simonorj.mc.phantomsmp;
|
||||
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
|
||||
class ConfigSaver {
|
||||
static final String REMOVE_TARGETING_RESTED_NODE = "remove-targeting-rested";
|
||||
static final String DISALLOW_SPAWNING_FOR_NODE = "disallow-targeting-for";
|
||||
static final String CONFIG_VERSION_NODE = "config-version";
|
||||
static final int version = 1;
|
||||
|
||||
private static final String HEADER =
|
||||
"# PhantomSMP by Simon Chuu\n" +
|
||||
"\n" +
|
||||
"# For help, follow the plugin project link below:\n" +
|
||||
"# https://github.com/SimonOrJ/PhantomSMP/\n";
|
||||
|
||||
private static final String REMOVE_TARGETING_RESTED =
|
||||
"# Remove phantoms that try to target player slept within three (Minecraft)\n" +
|
||||
"# days?\n" +
|
||||
"# true = remove phantom targeting rested player\n" +
|
||||
"# false = Keep phantoms (and make phantoms try to target another player)\n";
|
||||
|
||||
private static final String DISALLOW_SPAWNING_FOR =
|
||||
"# How many ticks since player rested should phantoms ignore the player?\n" +
|
||||
"# NOTE: Any value under 72000 (3 full Minecraft days) will essentially be\n" +
|
||||
"# ignored for phantom spawning. It will only have an effect on already\n" +
|
||||
"# spawned phantoms only.\n";
|
||||
|
||||
private static final String CONFIG_VERSION =
|
||||
"# Keeps track of configuration version -- do not change!";
|
||||
|
||||
static String saveToString(FileConfiguration config) {
|
||||
boolean remove = config.getBoolean(REMOVE_TARGETING_RESTED_NODE, true);
|
||||
int disallow = config.getInt(DISALLOW_SPAWNING_FOR_NODE, 72000);
|
||||
|
||||
return HEADER +
|
||||
"\n" +
|
||||
REMOVE_TARGETING_RESTED +
|
||||
REMOVE_TARGETING_RESTED_NODE +
|
||||
": " + remove +
|
||||
"\n\n" +
|
||||
DISALLOW_SPAWNING_FOR +
|
||||
DISALLOW_SPAWNING_FOR_NODE +
|
||||
": " + disallow +
|
||||
"\n\n" +
|
||||
CONFIG_VERSION +
|
||||
CONFIG_VERSION_NODE +
|
||||
": " + version +
|
||||
"\n";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
package com.simonorj.mc.phantomsmp;
|
||||
|
||||
import org.bukkit.Statistic;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Phantom;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.bukkit.event.entity.EntityDeathEvent;
|
||||
import org.bukkit.event.entity.EntityTargetLivingEntityEvent;
|
||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||
import org.bukkit.event.player.PlayerBedEnterEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.event.world.ChunkLoadEvent;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
|
||||
public class PhantomListener implements Listener {
|
||||
private static final String DISALLOW_SPAWN_PERM = "phantomsmp.disallowspawn";
|
||||
private static final String IGNORE_PERM = "phantomsmp.ignore";
|
||||
|
||||
private Map<Player, LinkedHashSet<Phantom>> playerPhantomMap = new HashMap<>();
|
||||
private Map<Phantom, Player> phantomPlayerMap = new HashMap<>();
|
||||
private PhantomSMP plugin;
|
||||
|
||||
PhantomListener() {
|
||||
this.plugin = PhantomSMP.getInstance();
|
||||
for (Player p : plugin.getServer().getOnlinePlayers()) {
|
||||
this.playerPhantomMap.put(p, new LinkedHashSet<>());
|
||||
}
|
||||
|
||||
// Initiate map
|
||||
for (World w : plugin.getServer().getWorlds()) {
|
||||
if (w.getEnvironment() != World.Environment.NORMAL)
|
||||
continue;
|
||||
|
||||
for (Entity e : w.getLivingEntities())
|
||||
if (e instanceof Phantom)
|
||||
addPhantom((Phantom) e);
|
||||
}
|
||||
}
|
||||
|
||||
void disable() {
|
||||
this.playerPhantomMap = null;
|
||||
this.phantomPlayerMap = null;
|
||||
this.plugin = null;
|
||||
}
|
||||
|
||||
private boolean phantomSpawnAllowed(Player p) {
|
||||
return p.getStatistic(Statistic.TIME_SINCE_REST) > plugin.disallowSpawningFor || p.hasPermission(DISALLOW_SPAWN_PERM);
|
||||
}
|
||||
|
||||
private boolean phantomIgnore(Player p) {
|
||||
return plugin.removeTargetingRested || p.hasPermission(IGNORE_PERM);
|
||||
}
|
||||
|
||||
private void addPhantom(Phantom phantom) {
|
||||
addPhantom(phantom, null);
|
||||
}
|
||||
|
||||
private void addPhantom(Phantom phantom, Cancellable e) {
|
||||
addPhantom(phantom, null, e);
|
||||
}
|
||||
|
||||
private void addPhantom(Phantom phantom, Player newTarget, Cancellable e) {
|
||||
if (newTarget == null && !(phantom.getTarget() instanceof Player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player p = newTarget != null ? newTarget : (Player) phantom.getTarget();
|
||||
|
||||
// Player rested before
|
||||
if (!phantomSpawnAllowed(p)) {
|
||||
if (e != null)
|
||||
e.setCancelled(true);
|
||||
|
||||
if (phantomIgnore(p))
|
||||
if (phantom.getCustomName() == null)
|
||||
phantom.remove();
|
||||
}
|
||||
|
||||
// Phantom spawn is legal
|
||||
playerPhantomMap.computeIfAbsent(p, k -> new LinkedHashSet<>()).add(phantom);
|
||||
phantomPlayerMap.put(phantom, p);
|
||||
}
|
||||
|
||||
private void removePlayerPhantom(Player p) {
|
||||
Iterator<Phantom> i = playerPhantomMap.get(p).iterator();
|
||||
while(i.hasNext()) {
|
||||
Phantom phantom = i.next();
|
||||
if (phantom.getTarget() == p) {
|
||||
phantomPlayerMap.remove(phantom);
|
||||
phantom.setTarget(null);
|
||||
}
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// Initiate when player joins
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void playerJoin(PlayerJoinEvent e) {
|
||||
playerPhantomMap.put(e.getPlayer(), new LinkedHashSet<>());
|
||||
}
|
||||
|
||||
// Reset when player leaves
|
||||
@EventHandler
|
||||
public void playerLeave(PlayerQuitEvent e) {
|
||||
Player p = e.getPlayer();
|
||||
|
||||
for (Phantom phantom : playerPhantomMap.get(p)) {
|
||||
if (phantom.getTarget() == p) {
|
||||
phantom.setTarget(null);
|
||||
phantomPlayerMap.remove(phantom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove phantoms when player sleeps
|
||||
@EventHandler
|
||||
public void playerUseBed(PlayerBedEnterEvent e) {
|
||||
if (e.isCancelled())
|
||||
return;
|
||||
|
||||
removePlayerPhantom(e.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void playerDied(PlayerDeathEvent e) {
|
||||
removePlayerPhantom(e.getEntity());
|
||||
}
|
||||
|
||||
// Check phantom when they spawn wrongly
|
||||
@EventHandler
|
||||
public void phantomSpawn(CreatureSpawnEvent e) {
|
||||
if (e.isCancelled() || !(e.getEntity() instanceof Phantom)) {
|
||||
return;
|
||||
}
|
||||
|
||||
addPhantom((Phantom) e.getEntity(), e);
|
||||
}
|
||||
|
||||
// Remove phantom that targets player who slept
|
||||
@EventHandler
|
||||
public void phantomTarget(EntityTargetLivingEntityEvent e) {
|
||||
if (e.isCancelled() || !(e.getEntity() instanceof Phantom && e.getTarget() instanceof Player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
addPhantom((Phantom) e.getEntity(), (Player) e.getTarget(), e);
|
||||
}
|
||||
|
||||
// Check phantom in loaded chunks
|
||||
@EventHandler
|
||||
public void phantomInLoadedChunk(ChunkLoadEvent e) {
|
||||
if (e.getWorld().getEnvironment() != World.Environment.NORMAL)
|
||||
return;
|
||||
|
||||
for (Entity ent : e.getChunk().getEntities())
|
||||
if (ent instanceof Phantom)
|
||||
addPhantom((Phantom) ent);
|
||||
}
|
||||
|
||||
// Check phantom on death
|
||||
@EventHandler
|
||||
public void phantomDied(EntityDeathEvent e) {
|
||||
if (!(e.getEntity() instanceof Phantom))
|
||||
return;
|
||||
|
||||
Phantom phantom = (Phantom) e.getEntity();
|
||||
|
||||
Player p = phantomPlayerMap.remove(phantom);
|
||||
if (p == null)
|
||||
return;
|
||||
|
||||
playerPhantomMap.get(p).remove(phantom);
|
||||
}
|
||||
}
|
|
@ -1,189 +1,57 @@
|
|||
package com.simonorj.mc.phantomsmp;
|
||||
|
||||
import org.bukkit.Statistic;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Phantom;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.bukkit.event.entity.EntityDeathEvent;
|
||||
import org.bukkit.event.entity.EntityTargetLivingEntityEvent;
|
||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||
import org.bukkit.event.player.PlayerBedEnterEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.event.world.ChunkLoadEvent;
|
||||
import com.google.common.base.Charsets;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.io.*;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class PhantomSMP extends JavaPlugin {
|
||||
private Map<Player, LinkedHashSet<Phantom>> playerPhantomMap = null;
|
||||
private Map<Phantom, Player> phantomPlayerMap = null;
|
||||
private boolean removeTargetingRested = true;
|
||||
private static final int TIME_SINCE_REST_PHANTOM_SPAWN = 72000;
|
||||
private static PhantomSMP instance = null;
|
||||
private PhantomListener listener = null;
|
||||
boolean removeTargetingRested;
|
||||
int disallowSpawningFor;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
PhantomSMP.instance = this;
|
||||
saveDefaultConfig();
|
||||
|
||||
this.playerPhantomMap = new HashMap<>();
|
||||
this.phantomPlayerMap = new HashMap<>();
|
||||
this.removeTargetingRested = getConfig().getBoolean("remove-targeting-rested", true);
|
||||
if (getConfig().getInt(ConfigSaver.CONFIG_VERSION_NODE) != ConfigSaver.version)
|
||||
saveConfig();
|
||||
|
||||
for (Player p : getServer().getOnlinePlayers()) {
|
||||
this.playerPhantomMap.put(p, new LinkedHashSet<>());
|
||||
}
|
||||
this.removeTargetingRested = getConfig().getBoolean(ConfigSaver.REMOVE_TARGETING_RESTED_NODE, true);
|
||||
this.disallowSpawningFor= getConfig().getInt(ConfigSaver.DISALLOW_SPAWNING_FOR_NODE, 72000);
|
||||
|
||||
// Initiate map
|
||||
for (World w : getServer().getWorlds()) {
|
||||
if (w.getEnvironment() != World.Environment.NORMAL)
|
||||
continue;
|
||||
|
||||
for (Entity e : w.getLivingEntities())
|
||||
if (e instanceof Phantom)
|
||||
addPhantom((Phantom) e);
|
||||
}
|
||||
|
||||
getServer().getPluginManager().registerEvents(new PhantomListener(), this);
|
||||
this.listener = new PhantomListener();
|
||||
getServer().getPluginManager().registerEvents(listener, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
playerPhantomMap = null;
|
||||
phantomPlayerMap = null;
|
||||
PhantomSMP.instance = null;
|
||||
listener.disable();
|
||||
listener = null;
|
||||
}
|
||||
|
||||
private void addPhantom(Phantom phantom) {
|
||||
addPhantom(phantom, null);
|
||||
}
|
||||
@Override
|
||||
public void saveConfig() {
|
||||
File configFile = new File(getDataFolder(), "config.yml");
|
||||
|
||||
private void addPhantom(Phantom phantom, Cancellable e) {
|
||||
addPhantom(phantom, null, e);
|
||||
}
|
||||
try {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
configFile.mkdirs();
|
||||
String data = ConfigSaver.saveToString(getConfig());
|
||||
|
||||
private void addPhantom(Phantom phantom, Player newTarget, Cancellable e) {
|
||||
if (newTarget == null && !(phantom.getTarget() instanceof Player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player p = newTarget != null ? newTarget : (Player) phantom.getTarget();
|
||||
|
||||
// Player rested before
|
||||
if (!phantomSpawnAllowed(p)) {
|
||||
if (e != null)
|
||||
e.setCancelled(true);
|
||||
|
||||
if (removeTargetingRested)
|
||||
if (phantom.getCustomName() == null)
|
||||
phantom.remove();
|
||||
}
|
||||
|
||||
// Phantom spawn is legal
|
||||
playerPhantomMap.computeIfAbsent(p, k -> new LinkedHashSet<>()).add(phantom);
|
||||
phantomPlayerMap.put(phantom, p);
|
||||
}
|
||||
|
||||
private void removePlayerPhantom(Player p) {
|
||||
Iterator<Phantom> i = playerPhantomMap.get(p).iterator();
|
||||
while(i.hasNext()) {
|
||||
Phantom phantom = i.next();
|
||||
if (phantom.getTarget() == p) {
|
||||
phantomPlayerMap.remove(phantom);
|
||||
phantom.setTarget(null);
|
||||
try (Writer writer = new OutputStreamWriter(new FileOutputStream(configFile), Charsets.UTF_8)) {
|
||||
writer.write(data);
|
||||
}
|
||||
i.remove();
|
||||
} catch (IOException e) {
|
||||
getLogger().log(Level.SEVERE, "Could not save config to " + configFile, e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean phantomSpawnAllowed(Player p) {
|
||||
return p.getStatistic(Statistic.TIME_SINCE_REST) > TIME_SINCE_REST_PHANTOM_SPAWN;
|
||||
}
|
||||
|
||||
public class PhantomListener implements Listener {
|
||||
// Initiate when player joins
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void playerJoin(PlayerJoinEvent e) {
|
||||
playerPhantomMap.put(e.getPlayer(), new LinkedHashSet<>());
|
||||
}
|
||||
|
||||
// Reset when player leaves
|
||||
@EventHandler
|
||||
public void playerLeave(PlayerQuitEvent e) {
|
||||
Player p = e.getPlayer();
|
||||
|
||||
for (Phantom phantom : playerPhantomMap.get(p)) {
|
||||
if (phantom.getTarget() == p) {
|
||||
phantom.setTarget(null);
|
||||
phantomPlayerMap.remove(phantom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove phantoms when player sleeps
|
||||
@EventHandler
|
||||
public void playerUseBed(PlayerBedEnterEvent e) {
|
||||
if (e.isCancelled())
|
||||
return;
|
||||
|
||||
removePlayerPhantom(e.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void playerDied(PlayerDeathEvent e) {
|
||||
removePlayerPhantom(e.getEntity());
|
||||
}
|
||||
|
||||
// Check phantom when they spawn wrongly
|
||||
@EventHandler
|
||||
public void phantomSpawn(CreatureSpawnEvent e) {
|
||||
if (e.isCancelled() || !(e.getEntity() instanceof Phantom)) {
|
||||
return;
|
||||
}
|
||||
|
||||
addPhantom((Phantom) e.getEntity(), e);
|
||||
}
|
||||
|
||||
// Remove phantom that targets player who slept
|
||||
@EventHandler
|
||||
public void phantomTarget(EntityTargetLivingEntityEvent e) {
|
||||
if (e.isCancelled() || !(e.getEntity() instanceof Phantom && e.getTarget() instanceof Player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
addPhantom((Phantom) e.getEntity(), (Player) e.getTarget(), e);
|
||||
}
|
||||
|
||||
// Check phantom in loaded chunks
|
||||
@EventHandler
|
||||
public void phantomInLoadedChunk(ChunkLoadEvent e) {
|
||||
if (e.getWorld().getEnvironment() != World.Environment.NORMAL)
|
||||
return;
|
||||
|
||||
for (Entity ent : e.getChunk().getEntities())
|
||||
if (ent instanceof Phantom)
|
||||
addPhantom((Phantom) ent);
|
||||
}
|
||||
|
||||
// Check phantom on death
|
||||
@EventHandler
|
||||
public void phantomDied(EntityDeathEvent e) {
|
||||
if (!(e.getEntity() instanceof Phantom))
|
||||
return;
|
||||
|
||||
Phantom phantom = (Phantom) e.getEntity();
|
||||
|
||||
Player p = phantomPlayerMap.remove(phantom);
|
||||
if (p == null)
|
||||
return;
|
||||
|
||||
playerPhantomMap.get(p).remove(phantom);
|
||||
}
|
||||
public static PhantomSMP getInstance() {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,16 @@
|
|||
# PhantomSMP by SimonOrJ
|
||||
# PhantomSMP by Simon Chuu
|
||||
|
||||
# Remove phantoms that try to target player slept within three (Minecraft) days?
|
||||
# For help, follow the plugin project link below:
|
||||
# https://github.com/SimonOrJ/PhantomSMP/
|
||||
|
||||
# Remove phantoms that try to target player slept within three (Minecraft)
|
||||
# days?
|
||||
# true = remove phantom targeting rested player
|
||||
# false = Keep phantoms (and make phantoms try to target another player)
|
||||
remove-targeting-rested: true
|
||||
|
||||
# How many ticks since player rested should phantoms ignore the player?
|
||||
# NOTE: Any value under 72000 (3 full Minecraft days) will essentially be
|
||||
# ignored for phantom spawning. It will only have an effect on already
|
||||
# spawned phantoms only.
|
||||
disallow-targeting-for: 72000
|
||||
|
|
|
@ -5,3 +5,14 @@ description: Advanced phantom mechanics especially for SMP servers
|
|||
main: com.simonorj.mc.phantomsmp.PhantomSMP
|
||||
website: https://github.com/SimonOrJ/PhantomSMP
|
||||
api-version: 1.13
|
||||
|
||||
permissions:
|
||||
phantomsmp.disallowspawn:
|
||||
description: Don't let phantom spawn on the player at all.
|
||||
default: false
|
||||
phantomsmp.ignore:
|
||||
description: >
|
||||
Don't let phantoms target the player or be removed.
|
||||
This will ignore `remove-targeting-rested` configuration option for the
|
||||
player and keep the phantom flying around.
|
||||
default: false
|
||||
|
|
Loading…
Reference in New Issue