diff --git a/README.md b/README.md index 84bce7d..fc6b066 100644 --- a/README.md +++ b/README.md @@ -22,13 +22,17 @@ This plugin took WEEKS to develop. The initial development took only a week, as Find the plugin on [BukkitDev](http://dev.bukkit.org/projects/elevators-v2)! ### How To Use -Place signs with [elevator] on line 1 on each floor. They will error (showing [???]) if the floor is too big or an invalid type. (You can change floor types and associated speeds in the config.) +Place signs with `[elevator]` on line 1 on each floor. They will error (showing [???]) if the floor is too big or an invalid type. (You can change floor types and associated speeds in the config.) -Use line 4 to add a custom floor name. If not specified, the default is in the format `Level [n]`. If the floor name matches this format, and [n] is a valid number, it will be automatically updated whenever the elevator is modified. (In case a floor was added in-between floors, changing the floor numbering.) +Use line 4 to add a custom floor name. If not specified, the default is in the format `Level [n]`. If the floor name matches this format, and `[n]` is a valid number, it will be automatically updated whenever the elevator is modified. (In case a floor was added in-between floors, changing the floor numbering.) -If you put [nodoor] on line 3, the block-based door feature will be disabled, and call signs will gain the ability to turn nearby levers on and off with the door timer, allowing you to create piston doors for your elevator. Nearby doors and gates will be opened/closed either way. +If you put `[nodoor]` on line 3, the block-based door feature will be disabled. Nearby doors and gates will be opened/closed either way. -You can create call-button signs with [call] on line 1. They will error if they're less than 1 or more than 3 blocks away from the elevator. +### Call Signs + +Create call-button signs with `[call]` on line 1. They will error if they're less than 1 or more than 3 blocks away from the elevator. They can be placed up to 1 block above and 3 blocks below a given floor. This is useful for hidden call signs that activate redstone. + +Any Redstone Lever next to a call sign will be activated when the doors open! #### User-made Tutorial: https://www.youtube.com/watch?v=9nzRgzJEpJ0 diff --git a/pom.xml b/pom.xml index d2315be..81e90b7 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.forestfire Elevators - 3.3.3 + 3.3.4 jar Elevators diff --git a/src/main/java/net/forestfire/elevators/Conf.java b/src/main/java/net/forestfire/elevators/Conf.java index 11c230e..a7c67a1 100644 --- a/src/main/java/net/forestfire/elevators/Conf.java +++ b/src/main/java/net/forestfire/elevators/Conf.java @@ -12,8 +12,11 @@ import java.io.Writer; import java.nio.charset.StandardCharsets; import java.util.Collection; +import java.util.List; import java.util.TreeMap; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import org.apache.commons.lang.StringEscapeUtils; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -38,35 +41,34 @@ public class Conf { //Global Variables: public static TreeMap elevators = new TreeMap<>(); -public static ChuList> movingFloors = new ChuList<>(); -public static BukkitTask CLTMR = null; public static Main plugin = null; -public static final Object API_SYNC = new Object(); -private static BukkitTask SVTMR = null; +public static ChuList> movingFloors=new ChuList<>(); +public static BukkitTask CLTMR=null; public static Main plugin=null; +public static final Object API_SYNC=new Object(); +private static BukkitTask SVTMR=null; //Global Config Settings: -public static String TITLE, CALL, ERROR, L_ST, L_END, NODOOR, MSG_GOTO_ST, MSG_GOTO_END, MSG_CALL, NOMV, M_ATLV, ATLV, - C_UP, UP, C_DOWN, DOWN; public static int RADIUS_MAX, MOVE_RES, DOOR_HOLD; public static ChuList BLOCKS; -public static ChuList BL_SPEED; public static Material DOOR_SET; public static boolean DEBUG = false; +public static String TITLE, CALL, ERROR, L_ST, L_END, NODOOR, MSG_GOTO_ST, MSG_GOTO_END, MSG_CALL, MSG_NOT_FOUND, +MSG_PERM, MSG_PERM_END, NOMV, M_ATLV, ATLV, C_UP, UP, C_DOWN, DOWN; public static int RADIUS_MAX, MOVE_RES, DOOR_HOLD; +public static ChuList BLOCKS; public static ChuList BL_SPEED; public static Material DOOR_SET; +public static boolean DEBUG=false; //Constants: -public static final String MSG_NEW_CONF = "§e[Elevators] §bCould not load config. Creating new config file..."; -public static final String MSG_ERR_CONF = "§e[Elevators] §cError while loading config!"; -public static final String MSG_DBG = "§e[Elevators] §r"; -public static final String MSG_ERR_ST = "§e[Elevators] §eError in §b"; -public static final String MSG_ERR_MID = "§e: §c"; -public static final String MSG_DEL_ST = "§e[Elevators] §b"; -public static final String MSG_DEL_END = " §esaved elevators were deleted because they were invalid!"; -public static final String CONFIG_PATH = "plugins/Elevators/config.yml"; -public static final Material AIR = Material.AIR; - -public static MemoryConfiguration defaults = new MemoryConfiguration(); -public static void initDefaults(Main _plugin) { +public static final String MSG_NEW_CONF="§e[Elevators] §bCould not load config. Creating new config file...", +MSG_ERR_CONF="§e[Elevators] §cError while loading config!", MSG_DBG="§e[Elevators] §r", +MSG_ERR_ST="§e[Elevators] §eError in §b", MSG_ERR_MID="§e: §c", MSG_DEL_ST="§e[Elevators] §b", +MSG_DEL_END=" §esaved elevators were deleted because they were invalid!", CONFIG_PATH="plugins/Elevators/config.yml"; +static final Material AIR = Material.AIR; + +static MemoryConfiguration defaults = new MemoryConfiguration(); +static void initDefaults(Main _plugin) { defaults.set("debug", false); defaults.set("title", "&1[&3Elevator&1]"); defaults.set("call", "&1[&3Call&1]"); defaults.set("error", "[&4???&r]"); defaults.set("selStart", "&8> &5"); defaults.set("selEnd", " &8<"); defaults.set("noDoor", "&1[nodoor]"); defaults.set("msgGotoStart", "&eTraveling to &a"); defaults.set("msgGotoEnd", "&e."); - defaults.set("msgCall", "&eCalling elevator."); defaults.set("noMove", "&4⦿ ⦿ ⦿ ⦿ ⦿ ⦿"); - defaults.set("mAtLevel", "&3⦿ ⦿ ⦿ ⦿ ⦿ ⦿"); defaults.set("atLevel", "&2⦿ ⦿ ⦿ ⦿ ⦿ ⦿"); + defaults.set("msgCall", "&eCalling elevator."); defaults.set("msgNotFound", "&cElevator not found! Try recreating it."); + defaults.set("msgPerm", "&cSorry, you need the &e"); defaults.set("msgPermEnd", " &cpermission!"); + defaults.set("noMove", "&4⦿ ⦿ ⦿ ⦿ ⦿ ⦿"); defaults.set("mAtLevel", "&3⦿ ⦿ ⦿ ⦿ ⦿ ⦿"); + defaults.set("atLevel", "&2⦿ ⦿ ⦿ ⦿ ⦿ ⦿"); defaults.set("callUp", "&3▲ ▲ ▲ ▲ ▲ ▲"); defaults.set("up", "&4△ △ △ △ △ △"); defaults.set("callDown", "&3▼ ▼ ▼ ▼ ▼ ▼"); defaults.set("down", "&4▽ ▽ ▽ ▽ ▽ ▽"); defaults.set("floorMaxRadius", 8); defaults.set("updateDelay", 50); defaults.set("doorHoldTime", 4000); @@ -75,11 +77,11 @@ public static void initDefaults(Main _plugin) { //------------------- Config Save & Load Functions ------------------- -public static void saveConf(boolean f) { +static void saveConf(boolean f) { if(SVTMR != null) SVTMR.cancel(); if(f) synchronized(API_SYNC) { doSaveConf(); } else SVTMR = plugin.setTimeout(Conf::doSaveConf, 200); -} public static void saveConf() { saveConf(false); } +} static void saveConf() { saveConf(false); } private static void doSaveConf() { SVTMR=null; File f=new File(CONFIG_PATH); String data; @@ -127,35 +129,34 @@ private static String newConf(File file) { return unpackFile("config.yml", file); } -public static Object loadConf() { try { +static Object loadConf() { try { File f=new File(CONFIG_PATH); YamlConfiguration conf; boolean pf=f.exists(); if(pf) conf=YamlConfiguration.loadConfiguration(f); else conf=new YamlConfiguration(); conf.setDefaults(defaults); movingFloors=new ChuList<>(); CLTMR=null; //Load Global Settings: DEBUG=conf.getBoolean("debug"); - TITLE=c(conf.getString("title")); - CALL=c(conf.getString("call")); - ERROR=c(conf.getString("error")); - L_ST=c(conf.getString("selStart")); - L_END=c(conf.getString("selEnd")); - NODOOR=c(conf.getString("noDoor")); + TITLE=conf.getString("title"); + CALL=conf.getString("call"); + ERROR=conf.getString("error"); + L_ST=conf.getString("selStart"); + L_END=conf.getString("selEnd"); + NODOOR=conf.getString("noDoor"); MSG_GOTO_ST=c(conf.getString("msgGotoStart")); MSG_GOTO_END=c(conf.getString("msgGotoEnd")); MSG_CALL=c(conf.getString("msgCall")); - - MSG_GOTO_ST=c(conf.getString("msgGotoStart")); - MSG_GOTO_END=c(conf.getString("msgGotoEnd")); - MSG_CALL=c(conf.getString("msgCall")); - - NOMV=c(StringEscapeUtils.unescapeJava(conf.getString("noMove"))); - M_ATLV=c(StringEscapeUtils.unescapeJava(conf.getString("mAtLevel"))); - ATLV=c(StringEscapeUtils.unescapeJava(conf.getString("atLevel"))); - C_UP=c(StringEscapeUtils.unescapeJava(conf.getString("callUp"))); - UP=c(StringEscapeUtils.unescapeJava(conf.getString("up"))); - C_DOWN=c(StringEscapeUtils.unescapeJava(conf.getString("callDown"))); - DOWN=c(StringEscapeUtils.unescapeJava(conf.getString("down"))); + MSG_NOT_FOUND=c(conf.getString("msgNotFound")); + MSG_PERM=c(conf.getString("msgPerm")); + MSG_PERM_END=c(conf.getString("msgPermEnd")); + + NOMV=StringEscapeUtils.unescapeJava(conf.getString("noMove")); + M_ATLV=StringEscapeUtils.unescapeJava(conf.getString("mAtLevel")); + ATLV=StringEscapeUtils.unescapeJava(conf.getString("atLevel")); + C_UP=StringEscapeUtils.unescapeJava(conf.getString("callUp")); + UP=StringEscapeUtils.unescapeJava(conf.getString("up")); + C_DOWN=StringEscapeUtils.unescapeJava(conf.getString("callDown")); + DOWN=StringEscapeUtils.unescapeJava(conf.getString("down")); RADIUS_MAX=conf.getInt("floorMaxRadius"); MOVE_RES=conf.getInt("updateDelay"); @@ -183,7 +184,7 @@ public static Object loadConf() { try { return pf?eCnt:"NOCONF"; } catch(Exception e) { err("loadConfig", e.getMessage()); return e.getMessage(); }} -public static void doConfLoad(CommandSender s) { +static void doConfLoad(CommandSender s) { Object err=loadConf(); if(err=="NOCONF") doSaveConf(); //Create New Config. else if(err instanceof Integer) { //Loaded Config Successfully. @@ -207,12 +208,12 @@ private static Material getMat(String m) throws Exception { catch(IllegalArgumentException e) { throw new Exception("No such material "+m); } } -public static String locToString(Location l) { +static String locToString(Location l) { return l.getWorld().getName()+"-"+l.getBlockX()+"-"+l.getBlockZ(); } //Open/close doors & gates: -public static void setDoor(Block b, boolean on) { +static void setDoor(Block b, boolean on) { if(b.getBlockData() instanceof Openable) { Openable d = (Openable)b.getBlockData(); if(d instanceof Door && ((Door)d).getHalf() != Bisected.Half.BOTTOM) return; @@ -232,50 +233,40 @@ else if(d instanceof TrapDoor) { l.getWorld().playSound(l,s,1,1); } -//Set state of levers: -public static void setPowered(Block b, boolean on) { +//Set state of levers +static void setPowered(Block b, boolean on) { if(b.getBlockData() instanceof Switch) { Switch s = (Switch)b.getBlockData(); s.setPowered(on); b.setBlockData(s); } } -//Write lines to sign: -public static void setSign(Block sign, String[] lines) { - Sign s = ((Sign)sign.getState()); - s.setLine(0, lines[0]==null?TITLE:lines[0]); s.setLine(1, lines[1]==null?"":lines[1]); - s.setLine(2, lines[2]==null?"":lines[2]); s.setLine(3, lines[3]==null?"":lines[3]); - s.update(); -} public static void setSign(Block sign, String lineOne) { - Sign s = ((Sign)sign.getState()); - s.setLine(0, lineOne==null?TITLE:lineOne); s.setLine(1, ""); - s.setLine(2, ""); s.setLine(3, ""); s.update(); +//Sign Read/Write +static void line(Block b, int i, String str) { + Sign s=(Sign)b.getState(); s.line(i,sc(str==null?"":str)); s.update(); } - -public static void setLine(Block sign, int l, String str) { - Sign s=((Sign)sign.getState()); s.setLine(l, str==null?"":str); s.update(); +static String line(Block b, int i) { return cs(((Sign)b.getState()).line(i)); } +static String[] lines(Block b) { + List c=((Sign)b.getState()).lines(); + return new String[]{cs(c.get(0)),cs(c.get(1)),cs(c.get(2)),cs(c.get(3))}; } - -//Read lines from sign: -public static String[] lines(Block sign) { - return ((Sign)sign.getState()).getLines(); +static void lines(Block b, String[] l) { + Sign s=(Sign)b.getState(); s.line(0,sc(l[0])); s.line(1,sc(l[1])); + s.line(2,sc(l[2])); s.line(3,sc(l[3])); s.update(); } -//Get block sign is attached to: -public static Block getSignBlock(Block s) { +//Get block sign is attached to +static Block getSignBlock(Block s) { World w=s.getWorld(); int x=s.getX(), y=s.getY(), z=s.getZ(); BlockFace f=((WallSign)s.getBlockData()).getFacing(); switch(f) { case NORTH: return w.getBlockAt(x,y,z+1); case SOUTH: return w.getBlockAt(x,y,z-1); - case WEST: return w.getBlockAt(x+1,y,z); case EAST: return w.getBlockAt(x-1,y,z); - default: return null; + case WEST: return w.getBlockAt(x+1,y,z); default: return w.getBlockAt(x-1,y,z); } } -//Ensure there is a solid block behind the sign. -public static void addSignBlock(Block s) { - Block b=Conf.getSignBlock(s); setDoorBlock(b,true); -} -public static void setDoorBlock(Block b, boolean on) { +//Ensure there is a solid block behind the sign +static void addSignBlock(Block s) { setDoorBlock(Conf.getSignBlock(s),true); } +static void setDoorBlock(Block b, boolean on) { Material m=b.getType(); if(on?!m.isSolid():m==Conf.DOOR_SET) b.setType(on?Conf.DOOR_SET:Conf.AIR); if(on && b.getBlockData() instanceof MultipleFacing) { //Connect block faces @@ -289,33 +280,36 @@ public static void setDoorBlock(Block b, boolean on) { } //Determine if sign or call sign was clicked on: -public static boolean isElevSign(Block b, ConfData ref, Player pl, String perm) { - if(!hasPerm(pl, perm)) return false; if(b.getBlockData() instanceof WallSign && TITLE.equals - (lines(b)[0])) { ref.data = Elevator.fromElevSign(b); return (ref.data!=null); } return false; +static boolean isElevSign(Block b, ConfData ref, Player p) { + if(!hasPerm(p,Main.PERM_USE,true)) return false; if(b.getBlockData() instanceof WallSign && TITLE.equals(line(b,0))) { + ref.data=Elevator.fromElevSign(b); if(ref.data==null) p.sendMessage(MSG_NOT_FOUND); return (ref.data!=null); + } return false; } -public static boolean isCallSign(Block b, ConfData ref, Player pl, String perm) { - if(!hasPerm(pl, perm)) return false; if(b.getBlockData() instanceof WallSign && CALL.equals - (lines(b)[0])) { ref.data = Elevator.fromCallSign(b); return (ref.data!=null); } return false; +static boolean isCallSign(Block b, ConfData ref, Player p) { + if(!hasPerm(p,Main.PERM_USE,true)) return false; if(b.getBlockData() instanceof WallSign && CALL.equals(line(b,0))) { + ref.data=Elevator.fromCallSign(b); if(ref.data==null) p.sendMessage(MSG_NOT_FOUND); return (ref.data!=null); + } return false; } -public static boolean isElevPlayer(Player pl, ConfData ref, String perm) { - if(!hasPerm(pl, perm)) return false; ref.data=Elevator.fromEntity(pl); return (ref.data!=null); +static boolean isElevPlayer(Player p, ConfData ref) { + if(!hasPerm(p,Main.PERM_USE,false)) return false; ref.data=Elevator.fromEntity(p); return (ref.data!=null); } //Find first null element in a RaichuList: -public static int findFirstEmpty(ChuList> list) { +static int findFirstEmpty(ChuList> list) { int l=list.length; for(int i=0; i pl = Bukkit.getOnlinePlayers(); - for(Player p: pl) if(hasPerm(p, Main.PERM_RELOAD)) p.sendMessage(msg); + String msg=MSG_DBG+str; Bukkit.getConsoleSender().sendMessage(msg); + Collection pl=Bukkit.getOnlinePlayers(); + for(Player p: pl) if(hasPerm(p,Main.PERM_RELOAD,false)) p.sendMessage(msg); } } - -public static void err(String func, String cause) { +static void err(String func, String cause) { if(DEBUG) { - String msg = MSG_ERR_ST+func+MSG_ERR_MID+cause; Bukkit.getConsoleSender().sendMessage(msg); - Collection pl = Bukkit.getOnlinePlayers(); - for(Player p: pl) if(hasPerm(p, Main.PERM_RELOAD)) p.sendMessage(msg); + String msg=MSG_ERR_ST+func+MSG_ERR_MID+cause; Bukkit.getConsoleSender().sendMessage(msg); + Collection pl=Bukkit.getOnlinePlayers(); + for(Player p: pl) if(hasPerm(p,Main.PERM_RELOAD,false)) p.sendMessage(msg); } } - -//------------------- PecacheuLib Functions ------------------- - -public static String c(String str) { - if(str == null) return null; - String[] clr = str.split("&"); StringBuilder c = new StringBuilder(clr[0]); - for(int i=1,l=clr.length; i> _sGroups, ChuList> _csGroups) { - floor = _floor; if(_sGroups==null) sGroups = new ChuList<>(); else sGroups = _sGroups; - if(_csGroups==null) csGroups = new ChuList<>(); else csGroups = _csGroups; + floor=_floor; if(_sGroups==null) sGroups=new ChuList<>(); else sGroups=_sGroups; + if(_csGroups==null) csGroups=new ChuList<>(); else csGroups=_csGroups; csData = new ChuList<>(); } @@ -40,7 +41,7 @@ public static Elevator fromSaveData(java.util.List data) { for(int i=1,l=data.size(),sX,sZ; i sList = Elevator.rebuildSignList(w, sX, sZ); + ChuList sList = Elevator.rebuildSignList(new Location(w,sX,0,sZ)); if(sList.length!=0) sGroups.add(sList); } if(sGroups.length==0) { Conf.err("fromSaveData", "No elevator signs found!"); return null; } @@ -49,14 +50,14 @@ public static Elevator fromSaveData(java.util.List data) { if(f==null) { Conf.err("fromSaveData", "No elevator floor detected!"); return null; } elev.floor=f; elev.rebuildCallSignList(null); //Special Modes: - if(Conf.NODOOR.equals(Conf.lines(dSign)[2])) elev.noDoor = true; //Enable NoDoor Mode. + if(Conf.NODOOR.equals(Conf.line(dSign,2))) elev.noDoor = true; //Enable NoDoor Mode. return elev; } public ChuList toSaveData() { - ChuList data = new ChuList<>(); data.add(floor.world.getName()); - for(int i=0,l=sGroups.length; i data=new ChuList<>(1+sGroups.length*2); data.add(floor.world.getName()); + for(ChuList g: sGroups) { + Block dSign=g.get(0); data.add(Integer.toString(dSign.getX())); data.add(Integer.toString(dSign.getZ())); } return data; @@ -64,9 +65,9 @@ public ChuList toSaveData() { //The names Bond. James Bond. public void selfDestruct() { - if(floor != null && sGroups.length > 0 && sGroups.get(0).length > 0) { resetElevator(true); setDoors(sGroups.get(0).get(0).getY(), false); } - for(ChuList c: csGroups) for(Block s: c) s.setType(Conf.AIR); - for(String s: Conf.elevators.keySet()) if(this.equals(Conf.elevators.get(s))) Conf.elevators.remove(s); + if(floor != null && sGroups.length>0 && sGroups.get(0).length>0) { resetElevator(true); setDoors(0,false); } + floor=null; for(ChuList c: csGroups) for(Block s: c) s.setType(Conf.AIR); + Conf.elevators.entrySet().remove(this); } public int yMin() { return sGroups.get(0).get(0).getY()-2; } @@ -77,32 +78,46 @@ public void selfDestruct() { //Locate elev signs at X,Z pos. Include Y pos for new sign detection. public static ChuList rebuildSignList(Location l) { World w=l.getWorld(); int x=l.getBlockX(), y=l.getBlockY(), z=l.getBlockZ(); - ChuList sList = new ChuList<>(); for(int h=w.getMinHeight(); h sList=new ChuList<>(); for(int h=w.getMinHeight(); h rebuildSignList(World w, int x, int z) { return rebuildSignList(new Location(w, x, 0, z)); } +} public static ChuList rebuildSignList(Block b) { return rebuildSignList(b.getLocation()); } //Locate all call signs around elevator. Include newLoc for new sign detection. -void rebuildCallSignList(Location newLoc) { - ChuList sList = sGroups.get(0); int j=0,g=sList.length; csGroups = new ChuList<>(g); +void rebuildCallSignList(Location nLoc) { + ChuList sList=sGroups.get(0); int j=0,g=sList.length; + Floor f=floor; World w=f.world; csGroups=new ChuList<>(g); for(; j()); //Scan perimeter for call signs: - int sY=sList.get(j).getY(),a; for(int dXZ=0; dXZ<4; dXZ++) { + int dy=sList.get(j).getY(),dXZ,xP,zP,a; csGroups.set(j, new ChuList<>()); + for(int y=dy-2; y<=dy+1; y++) for(dXZ=0; dXZ<4; dXZ++) { //Scan perimeter for call signs: a=(dXZ==0?0:1); - for(int xP=floor.xMin-a; xPfloor.xMin-2; xP--) chkSign(floor.world.getBlockAt(xP, sY, floor.zMax+1+dXZ), j, newLoc); - for(int zP=floor.zMax+a; zP>floor.zMin-2; zP--) chkSign(floor.world.getBlockAt(floor.xMin-1-dXZ, sY, zP), j, newLoc); + for(xP=f.xMin-a; xPf.xMin-2; xP--) chkSign(w.getBlockAt(xP, y, f.zMax+1+dXZ), j, nLoc); + for(zP=f.zMax+a; zP>f.zMin-2; zP--) chkSign(w.getBlockAt(f.xMin-1-dXZ, y, zP), j, nLoc); } } } private void chkSign(Block s, int i, Location nl) { - if(s.getBlockData() instanceof WallSign && (Conf.CALL.equals(Conf.lines(s)[0]) + if(s.getBlockData() instanceof WallSign && (Conf.CALL.equals(Conf.line(s,0)) || (nl!=null && s.getLocation().equals(nl)))) csGroups.get(i).add(s); } +//Update Sign Level Numbers for Non-Custom-Named Signs +void updateSignNames(SignChangeEvent e) { + Block eb; String el=null; int ei=-1; if(e!=null) { + eb=e.getBlock(); el=Conf.cs(e.line(3)); //Update changed sign + for(ChuList g: sGroups) if((ei=g.indexOf(eb)) != -1) break; + if(el.length()<1 || el.matches("^Level [0-9]+$")) e.line(3,Conf.sc(el="Level "+(ei+1))); + } + for(ChuList g: sGroups) for(int f=0,d=g.length; f sList = e.sGroups.get(0); for(int j=0,g=sList.length; j1) continue; for(int dXZ=0,a; dXZ<4; dXZ++) { //Scan perimeter for call signs: a=(dXZ==0?0:1); if((z == f.zMin-1-dXZ && x >= f.xMin-a && x < f.xMax+2) || (x == f.xMax+1+dXZ && z >= f.zMin-a && z < f.zMax+2) || @@ -131,6 +146,16 @@ public static CSData fromCallSign(Block sign) { } } Conf.err("fromCallSign", "Elevator not detected for sign: "+sign); return null; } +/* + for(int j=0,g=sList.length; j= fl.xMin-a && x < fl.xMax+2) || (x == fl.xMax+1+dXZ && z >= fl.zMin-a && z < fl.zMax+2) || + (z == fl.zMax+1+dXZ && x <= fl.xMax+a && x > fl.xMin-2) || (x == fl.xMin-1-dXZ && z <= fl.zMax+a && z > fl.zMin-2)) return new CSData(elev, j); + } + } + } Conf.err("fromCallSign", "Elevator not detected for sign: "+sign); return null; +}*/ //Get elevator for block, if any. public static Elevator fromElevBlock(Block bl) { @@ -172,86 +197,92 @@ public static Elevator fromDoor(Location l) { //-- Elevator Movement Functions: +//Get current floor +public int getFloor() { + int f=getLevel()+2; ChuList sl=sGroups.get(0); + for(int i=0,l=sl.length; i sList = sGroups.get(0); World world = sList.get(0).getWorld(); int xPos = sList.get(0).getX(), zPos = sList.get(0).getZ(); - for(int y=yMin(),l=yMax(); y sList = sGroups.get(0); boolean locked = floor.moving; - ChuList csInd = new ChuList<>(sList.length); - for(int m=0,k=sList.length,fNum=-1; m= fLvl) fNum = m; //Get level from floor height. - if(m == fNum) ind = (fDir==2||locked) ? Conf.M_ATLV : Conf.ATLV; //Elevator is on level. - else if(locked) { if(fDir>0) { //Going Up. - if(m > fNum && m == sNum) ind = Conf.C_UP; //Elevator is below us and going to our floor. - else ind = Conf.UP; //Elevator is above us or not going to our floor. + ChuList sl=sGroups.get(0),cl; boolean lck=floor.moving; + ChuList csInd=new ChuList<>(sl.length); + for(int m=0,k=sl.length,fNum=-1; m= fLvl) fNum=m; //Get level from floor height. + if(m == fNum) ind=(fDir==2||lck)?Conf.M_ATLV:Conf.ATLV; //Elevator is on level. + else if(lck) { if(fDir>0) { //Going Up. + if(m > fNum && m == sNum) ind=Conf.C_UP; //Elevator is below us and going to our floor. + else ind=Conf.UP; //Elevator is above us or not going to our floor. } else { //Going Down. - if(fNum == -1 && m == sNum) ind = Conf.C_DOWN; //Elevator is above us and going to our floor. - else ind = Conf.DOWN; //Elevator is below us or not going to our floor. + if(fNum == -1 && m == sNum) ind=Conf.C_DOWN; //Elevator is above us and going to our floor. + else ind=Conf.DOWN; //Elevator is below us or not going to our floor. }} - csInd.set(m, ind); csData = csInd; - if(csGroups.get(m)!=null) for(int i=0,l=csGroups.get(m).length; i g: sGroups) for(Block s: g) Conf.line(s,1,nf); } public FList getFloors() { - ChuList ds=sGroups.get(0); String s,sel=Conf.lines(ds.get(0))[1]; int n=0; + ChuList ds=sGroups.get(0); String s,sel=Conf.line(ds.get(0),1); int n=0; if(sel.length()!=0) sel=sel.substring(Conf.L_ST.length(), sel.length()-Conf.L_END.length()); int i=0,l=ds.length; ChuList fn=new ChuList<>(l); - for(; i { - setDoors(level, false); Conf.CLTMR = null; - }, Conf.DOOR_HOLD); +public void doorTimer(int flr) { + setDoors(flr, true); if(Conf.CLTMR != null) Conf.CLTMR.cancel(); + Conf.CLTMR = Conf.plugin.setTimeout(() -> { setDoors(flr, false); Conf.CLTMR=null; }, Conf.DOOR_HOLD); } //-- Utility Functions: //Remove all blocks in elevator: public void resetElevator(boolean noFloor) { - int yMin = this.yMin(), yMax = this.yMax(); World world = floor.world; - for(int y=yMin; y g: sGroups) for(Block s: g) if(s.equals(sign)) return true; return false; } //Open/close elevator doors. -public void setDoors(int h, boolean on) { +public void setDoors(int flr, boolean on) { + int h=sGroups.get(0).get(flr).getY(); Floor f=floor; World w=f.world; Block b; for(int yP=h-1; yP<=h+1; yP++) { //Cycle Around Elevator Perimeter: for(int xP=f.xMin; xPf.xMin-2; xP--) { b=w.getBlockAt(xP, yP, f.zMax+1); if(!noDoor) setBDoor(b,on); Conf.setDoor(b,on); } for(int zP=f.zMax; zP>f.zMin-2; zP--) { b=w.getBlockAt(f.xMin-1, yP, zP); if(!noDoor) setBDoor(b,on); Conf.setDoor(b,on); } } - int fNum=-1; for(int q=0,m=sGroups.get(0).length; qfLevel); double step = (double)speed * ((double)Conf.MOVE_RES/1000) * (moveDir?1:-1); - - if(Conf.CLTMR != null) { Conf.CLTMR.cancel(); Conf.CLTMR = null; } +public void gotoFloor(int from, int to, boolean msg) { + if(Conf.CLTMR != null) { Conf.CLTMR.cancel(); Conf.CLTMR=null; } - for(int i=0,l=sGroups.get(0).length; ifrom); double step=(double)speed*((double)Conf.MOVE_RES/1000)*(moveDir?1:-1); + ChuList sl=sGroups.get(0); - Conf.dbg("FROM: "+fLevel+", TO: "+sLevel+" ("+selNum+"), STEP: "+step); + for(int i=0,l=sl.length; i { - int fID = floor.addFloor(fLevel, true, false); - GotoTimer timer = new GotoTimer(this, fLevel, sLevel, selNum, speed, step, fID, msg); + GotoTimer timer=new GotoTimer(this, fLev, tLev, to, speed, step, msg); Conf.plugin.setInterval(timer, Conf.MOVE_RES); }, 500); } @@ -304,8 +335,9 @@ class GotoTimer extends BukkitRunnable { private final int sLev, sNum, fID; private final double step, accel; private double fPos; private final ChuList eList = new ChuList<>(5); -GotoTimer(Elevator _e, int fp, int sl, int sn, double spd, double st, int id, boolean m) { - el=_e; step=st; fPos=fp; sLev=sl; sNum=sn; fID=id; accel=spd*(el.moveDir?1:-1)/20; +GotoTimer(Elevator _e, int fp, int tl, int to, double spd, double st, boolean m) { + el=_e; step=st; fPos=fp; sLev=tl; sNum=to; accel=spd*(el.moveDir?1:-1)/20; + fID=el.floor.addFloor(fp, true, false); FList fl=el.getFloors(); String name=fl.fl.get(fl.sn); //Find entities in elevator: for(Entity e: el.floor.world.getEntitiesByClass(LivingEntity.class)) if(el.entityInElev(e)) { @@ -336,7 +368,7 @@ public void run() { synchronized(Conf.API_SYNC) { this.cancel(); el.floor.deleteFloor(fID); pl.setTimeout(() -> { el.floor.addFloor(sLev, false, false); setEntities(true, 0, sLev); //Restore solid floor. el.updateCallSigns(sLev+2); pl.setTimeout(() -> { - el.floor.moving=false; el.updateCallSigns(sLev+2); el.doorTimer(sLev+2); + el.floor.moving=false; el.updateCallSigns(sLev+2); el.doorTimer(sNum); }, 500); }, 50); } else fPos += step; diff --git a/src/main/java/net/forestfire/elevators/Main.java b/src/main/java/net/forestfire/elevators/Main.java index b756087..1c05f24 100644 --- a/src/main/java/net/forestfire/elevators/Main.java +++ b/src/main/java/net/forestfire/elevators/Main.java @@ -29,10 +29,10 @@ import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitTask; +import java.util.Collection; + public class Main extends JavaPlugin implements Listener { -static final String PERM_USE = "elevators.use"; -static final String PERM_CREATE = "elevators.create"; -static final String PERM_RELOAD = "elevators.reload"; +static final String PERM_USE="elevators.use", PERM_CREATE = "elevators.create", PERM_RELOAD="elevators.reload"; public static Elevator LAST_ELEV; @Override @@ -41,44 +41,49 @@ public void onEnable() { getServer().getPluginManager().registerEvents(this, this); Bukkit.getConsoleSender().sendMessage(Conf.MSG_DBG+"§dElevators Plugin Loaded!"); } - @Override public void onDisable() { Conf.saveConf(true); HandlerList.unregisterAll(); } - @Override public boolean onCommand(CommandSender s, Command c, String l, String[] a) { if(c.getName().equalsIgnoreCase("elev")) { - if(a.length > 0 && a[0].equalsIgnoreCase("reset")) { - if(LAST_ELEV != null) { LAST_ELEV.resetElevator(a.length > 1); s.sendMessage("Last elevator reset."); } + if(a.length == 1 && a[0].equals("list")) { + Collection el=Conf.elevators.values(); + s.sendMessage(el.size()+" Elevators:"); for(Elevator e: el) { + Floor f=e.floor; Block b=e.sGroups.get(0).get(0); s.sendMessage("Elevator in §d"+f.world.getName() + +" §rat §b["+b.getX()+","+b.getZ()+"]§r; Size: §b"+(f.xMax-f.xMin)+"x"+(f.zMax-f.zMin)); + } + } else if(a.length>0 && a[0].equals("reset")) { + if(LAST_ELEV != null) { LAST_ELEV.resetElevator(a.length>1); s.sendMessage("Last elevator reset."); } else s.sendMessage("§cNo last elevator."); - } else if(a.length == 1 && a[0].equalsIgnoreCase("reload")) { + } else if(a.length == 1 && a[0].equals("reload")) { setTimeout(() -> Conf.doConfLoad(s), 200); - } else s.sendMessage("§cUsage: /elev reload"); + } else s.sendMessage("§cUsage: /elev "); return true; } return false; } -//JavaScript-like Timer Functionality: -//Call .cancel() on the returned value to cancel. - +//JavaScript-like Timer Functionality +//Call .cancel() on the returned value to cancel public BukkitTask setTimeout(Runnable f, long ms) { return new BukkitRunnable() { public void run() { synchronized(Conf.API_SYNC) { f.run(); }}}.runTaskLater(this, ms/50); } -public BukkitTask setInterval(BukkitRunnable f, long ms) { ms/=50; return f.runTaskTimer(this,ms,ms); } +public void setInterval(BukkitRunnable f, long ms) { ms/=50; f.runTaskTimer(this,ms,ms); } //------------------- Elevator Create Sign Events ------------------- @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onSignChange(SignChangeEvent e) { Block sign = e.getBlock(); synchronized(Conf.API_SYNC) { if(sign.getBlockData() instanceof WallSign) { - if(e.getLine(0).equalsIgnoreCase("[call]") && Conf.hasPerm(e.getPlayer(), PERM_CREATE)) { //Call Sign: - e.setLine(0, "> ERROR <"); e.setLine(1, ""); e.setLine(2, ""); + if(e.getLine(0).equalsIgnoreCase("[call]") && Conf.hasPerm(e.getPlayer(), PERM_CREATE, true)) { //Call Sign: + e.line(0,Conf.sc("> ERROR <")); e.line(1,Conf.sc("")); e.line(2,Conf.sc("")); //Is sign in elevator? - CSData ret = Elevator.fromCallSign(sign); if(ret==null) { e.setLine(0, Conf.ERROR); Conf.err("onSignChange:CallSign", "No elevator found!"); return; } + CSData ret = Elevator.fromCallSign(sign); if(ret==null) { + e.line(0,Conf.sc(Conf.ERROR)); Conf.err("onSignChange:CallSign", "No elevator found!"); return; + } Elevator elev = ret.elev; int csNum = ret.index; if(elev.floor.moving) { e.setCancelled(true); sign.setType(Conf.AIR); Conf.err("onSignChange:CallSign", "Elevator is moving!"); return; } @@ -87,93 +92,75 @@ public BukkitTask setTimeout(Runnable f, long ms) { //Update call signs: elev.updateCallSigns(elev.getLevel()); - e.setLine(0, Conf.CALL); e.setLine(3, elev.csData.get(csNum)); + e.line(0,Conf.sc(Conf.CALL)); e.line(3,Conf.sc(elev.csData.get(csNum))); - } else if(e.getLine(0).equalsIgnoreCase("[elevator]") && Conf.hasPerm(e.getPlayer(), PERM_CREATE)) { //Elevator Sign: - e.setLine(0, "> ERROR <"); e.setLine(1, ""); + } else if(e.getLine(0).equalsIgnoreCase("[elevator]") && Conf.hasPerm(e.getPlayer(), PERM_CREATE, true)) { //Elevator Sign: + e.line(0,Conf.sc("> ERROR <")); e.line(1,Conf.sc("")); //Is sign in elevator? - Elevator elev = Elevator.fromElevSign(sign); - - //Build sign list: - ChuList sList = Elevator.rebuildSignList(sign.getLocation()); int col=-1; + Elevator elev=Elevator.fromElevSign(sign); ChuList sList; int col=-1; if(elev!=null) { //Existing Elevator: if(elev.floor.moving) { e.setCancelled(true); sign.setType(Conf.AIR); Conf.err("onSignChange:ElevSign", "Elevator is moving!"); return; } - for(int i=0,l=elev.sGroups.length; i oList = elev.sGroups.get(k); int sX = oList.get(0).getX(), sZ = oList.get(0).getZ(); - WallSign d = (WallSign)sList.get(0).getBlockData(); World w = elev.floor.world; - for(int i=0,l=oList.length; i(sl); for(int i=0; i sRef = elev.sGroups.get(0); int sX = sList.get(0).getX(), sZ = sList.get(0).getZ(); - WallSign d = (WallSign)sList.get(0).getBlockData(); World w = elev.floor.world; - for(int i=0,l=sList.length; i(sl); for(int i=0; i sRef=elev.sGroups.get(0); int sl=sRef.length; sList=new ChuList<>(sl); + for(int i=0; i Conf.line(s,2,"")); //NoDoor + //Validate Sign Placement: - boolean cErr = false; for(int i=0; i 0 && (sList.get(i).getY() - sList.get(i-1).getY()) < 3) { //Signs too close! - Conf.setLine(sList.get(i), 0, Conf.ERROR); - if(sList.get(i).getLocation().equals(sign.getLocation())) cErr=true; sList.remove(i); i--; + boolean cErr=false; for(int i=0; i0 && (sList.get(i).getY()-sList.get(i-1).getY()) < 3) { //Signs too close! + if(sList.get(i).getY()==sign.getY()) cErr=true; + for(ChuList g: elev.sGroups) Conf.lines(g.remove(i),new String[]{Conf.ERROR,"","",""}); i--; } } - //Update Elevator Data: - if(col == -1) { elev.sGroups = new ChuList>(sList); } else elev.sGroups.set(col, sList); - - //Line 2 Special Modes: - if(elev.noDoor) elev.sGroups.get(0).forEach((s) -> Conf.setLine(s, 2, "")); - //Set modes: - String sLine = e.getLine(2); - if(elev.noDoor || sLine.equalsIgnoreCase("[nodoor]")) { //Enable NoDoor Mode: - elev.noDoor = true; Block first = elev.sGroups.get(0).get(0); - if(first.equals(sign)) e.setLine(2, Conf.NODOOR); - else { Conf.setLine(first, 2, Conf.NODOOR); e.setLine(2, ""); } - } else e.setLine(2, ""); - - //Update Sign Level Numbers for Non-Custom-Named Signs: - for(int k=0,m=elev.sGroups.length; k sList = Elevator.rebuildSignList(b.getLocation()); elev.resetElevator(); + ChuList sList = Elevator.rebuildSignList(b); elev.resetElevator(); //Find sGroups index: - int ind = -1; for(int i=0,l=elev.sGroups.length; i 1) { //Delete Whole Columns: + if(elev.sGroups.length>1) { //Delete Whole Columns: for(int i=0,l=sList.length; i cs = elev.csGroups.get(sInd); if(cs != null) for(int h=0,d=cs.length; h permission: elevators.reload - permission-message: You don't have permission to do that! permissions: elevators.use: default: true