Sign converting 1.7.9 -> 1.8.8

Discussion in 'Plugin Development' started by rcth, Sep 19, 2015.

Thread Status:
Not open for further replies.
  1. Offline

    rcth

    Hello fellow members,

    I just updated my 1.7.9 server to 1.8.8. It took a while, but everything seems finally done.

    However...

    Signs are messed up!

    I use the Traincarts plugin in my server and therefor use signs like [train], [!train], [+train], [cart], [!cart] and [+cart]. I also have my own plugin with tags on signs like [detector].

    The problem is this: All the square brackets ( [ and ] ) are gone! Somehow, [train] became train, [+train] became +train etc. etc. It happened to all signs in the world!

    I've added the exact same map from the 1.7.9 version also in Singleplayer and opened it in 1.8.8, but these signs have also changed. So it has nothing really to do with Bukkit, Spigot or whatever.

    I've written a simple solution (right click a sign, if it has one of the deformed tags on it, it will fix that sign automatically), but with the amount of signs we have in the world, it's impossible to fix them all manually. I've thought of an automatic method, but I'm not really sure how I should do this.

    It goes as following:
    ¤ Get all signs in a world
    ¤ Check the first line
    ¤ Check if it has the deformed tag
    ¤ If so, apply fix

    This method should run at plugin startup, so it would fix everything immediatly.

    However... Is this even possible? To get all the signs in a world? If so, how?

    Thanks in advance.
     
  2. Offline

    bean710

    @rcth You could scan through all of the blocks in a world and then use the method that you did for the right click thing, but I do not recommend it because it will cause mass amounts of lag.

    Edit: is it possible for you to load all of the chunks that you need and then run a command?
     
  3. Offline

    Impelon

    Hmm... Well as you can't get a list of a particular blocktype specifically (I mean as an Inbuild-Bukkit-Method) and also it would take an enormous time to check all of the world, I would check only a certain area of the world.

    Like this:


    Code:
    Location pos1; //set this to be one corner of the desired area
    Location pos2; //set this to be the other corner
    
    List<Location> signs = new ArrayList<Location>(); //list of all signs within the area
    
    pos1.setX(Math.floor(pos1.getX()));
    pos1.setY(Math.floor(pos1.getY()));
    pos1.setZ(Math.floor(pos1.getZ()));
    pos2.setX(Math.floor(pos2.getX()));
    pos2.setY(Math.floor(pos2.getY()));
    pos2.setZ(Math.floor(pos2.getZ()));
    if (pos1.getWorld().equals(pos2.getWorld())) { //only do this if the Locations are within the same World
        double xMin = Math.min(pos1.getX(), pos2.getX());
        double yMin = Math.min(pos1.getY(), pos2.getY());
        double zMin = Math.min(pos1.getZ(), pos2.getZ());
        double xMax = Math.max(pos1.getX(), pos2.getX());
        double yMax = Math.max(pos1.getY(), pos2.getY());
        double zMax = Math.max(pos1.getZ(), pos2.getZ());
        for (Integer x = 0; x <= Math.abs(xMax - xMin); x = x + 1) {
            for (Integer y = 0; y <= Math.abs(yMax - yMin); y = y + 1) {
                for (Integer z = 0; z <= Math.abs(zMax - zMin); z = z + 1) {
                    Location currentPos = new Location(pos1.getWorld(), xMin + x, yMin + y, zMin + z);
                    if (currentPos.getBlock().getType().equals(Material.SIGN) || currentPos.getBlock().getType().equals(Material.SIGN_POST)) //check if the Location is a sign
                        signs.add(currentPos); //add Location to List of Sign Locations
                }
            }
        }
    }
    
     
  4. Offline

    rcth

    Yes, I was thinking of such a method, however Signs aren't Blocks as far as I know, but Blockstates.

    The current method I'm using in the PlayerInteractEvent:
    Code:
    if (event.getAction() == Action.RIGHT_CLICK_BLOCK) {
    			if (event.getClickedBlock().getState() instanceof Sign) {
    				Sign sign = (Sign) event.getClickedBlock().getState();
    				
    				String title = sign.getLine(0);
    				String titleNew = title;
    				if (title.equalsIgnoreCase("train")) {
    					titleNew = "[train]";
    				} else if (title.equalsIgnoreCase("!train")) {
    					titleNew = "[!train]";
    				} else if (title.equalsIgnoreCase("+train")) {
    					titleNew = "[+train]";
    				} else if (title.equalsIgnoreCase("cart")) {
    					titleNew = "[cart]";
    				} else if (title.equalsIgnoreCase("!cart")) {
    					titleNew = "[!cart]";
    				} else if (title.equalsIgnoreCase("+cart")) {
    					titleNew = "[+cart]";
    				}
    				
    				if (event.getPlayer().hasPermission("themecraft.admin")) {
    					if (!titleNew.equalsIgnoreCase(title)) {
    						sign.setLine(0, titleNew);
    						sign.update();
    						event.getPlayer().sendMessage(ChatColor.GREEN + "Sign Fixer: done.");
    					}
    				}
    			}
    		}
    
    But doing so for each sign manually is just too much work, as there are probably over 300 of such signs, some of them hidden somewhere, so it's hard to find all.
     
  5. Offline

    Impelon

    @rcth
    Yes, true, my fault ^^ srry took some code from one of my projects and rapidly changed it up to fit your benefits; totally forgot about the whole sign-blockstate-thingy... But basically change the last if-clause I did there to this:


    Code:
    if (currentpos.getBlock().getState().getType().equals(Material.SIGN) || currentpos.getBlock().getState().getType().equals(Material.SIGN_POST))
        signs.add(currentPos);
    
    You could even change my initial idea of the List signs storing the Location to storing the BlockState... then it would look like this:


    Code:
    List<BlockState> signs = new ArrayList<BlockState>();
    
    //rest of code as in first example
    
    if (currentpos.getBlock().getState().getType().equals(Material.SIGN) || currentpos.getBlock().getState().getType().equals(Material.SIGN_POST))
        signs.add(currentPos.getBlock().getState());
    Edit:

    Well and then basically let your code run thorugh the List...
    And like you've said, put it into the loading method!
     
  6. Offline

    rcth

    I've changed the code a bit to run when used a specific command, not on server start.

    Code:
    public void fixsigns(Player player) {
    		player.sendMessage("TC Signfixer started.");
    		List<BlockState> signs = new ArrayList<BlockState>();
    		Location pos1 = new Location(Bukkit.getWorld("themecraft"), -381.0D, 4.0D, 479.0D);
    		Location pos2 = new Location(Bukkit.getWorld("themecraft"), 468.0D, 131.0D, -679.0D);
    		
    		pos1.setX(Math.floor(pos1.getX()));
    		pos1.setY(Math.floor(pos1.getY()));
    		pos1.setZ(Math.floor(pos1.getZ()));
    		pos2.setX(Math.floor(pos2.getX()));
    		pos2.setY(Math.floor(pos2.getY()));
    		pos2.setZ(Math.floor(pos2.getZ()));
    		if (pos1.getWorld().equals(pos2.getWorld())) {
    			double xMin = Math.min(pos1.getX(), pos2.getX());
    			double yMin = Math.min(pos1.getY(), pos2.getY());
    			double zMin = Math.min(pos1.getZ(), pos2.getZ());
    			double xMax = Math.max(pos1.getX(), pos2.getX());
    			double yMax = Math.max(pos1.getY(), pos2.getY());
    			double zMax = Math.max(pos1.getZ(), pos2.getZ());
    			for (Integer x = 0; x <= Math.abs(xMax - xMin); x = x + 1) {
    				for (Integer y = 0; y <= Math.abs(yMax - yMin); y = y + 1) {
    					for (Integer z = 0; z <= Math.abs(yMax - yMin); z = z + 1) {
    						Location currentPos = new Location(pos1.getWorld(), xMin + x, yMin + y, zMin + z);
    						if (currentPos.getBlock().getState().getType().equals(Material.SIGN) || currentPos.getBlock().getState().getType().equals(Material.SIGN_POST) || currentPos.getBlock().getState().getType().equals(Material.WALL_SIGN)) {
    							signs.add(currentPos.getBlock().getState());
    						}
    					}
    				}
    			}
    		}
    		
    		int foundDeformed = 0;
    		int found = 0;
    		for (BlockState state : signs) {
    			if (state instanceof Sign) {
    				Sign sign = (Sign)state;
    				
    				String title = sign.getLine(0);
    				String titleNew = title;
    				if (title.equalsIgnoreCase("train")) {
    					titleNew = "[train]";
    				} else if (title.equalsIgnoreCase("!train")) {
    					titleNew = "[!train]";
    				} else if (title.equalsIgnoreCase("+train")) {
    					titleNew = "[+train]";
    				} else if (title.equalsIgnoreCase("cart")) {
    					titleNew = "[cart]";
    				} else if (title.equalsIgnoreCase("!cart")) {
    					titleNew = "[!cart]";
    				} else if (title.equalsIgnoreCase("+cart")) {
    					titleNew = "[+cart]";
    				}
    				
    				if (!titleNew.equalsIgnoreCase(title)) {
    					sign.setLine(0, titleNew);
    					sign.update();
    					foundDeformed++;
    				}
    				found++;
    			}
    		}
    		player.sendMessage("TC Signfixer finished. Total signs found: " + found + ". Total signs fixed: " + foundDeformed);
    	}
    
    The found variable returns the amount of signs in the area that have been found. This runs correctly. However, there are 0 signs found with the wrong tags, even when I just placed a new one.

    Why doesn't this work correctly? It's the same "sign-change line" code I've used before, but I've added the counters too.
     
  7. Offline

    Impelon

    Maybe let it print out the title and the titleNew, after the check has been done, so you know what it did exactly?
     
  8. Offline

    rcth

    Debug I've added shows me some interesting information. Like, the signs somehow DO have the brackets, but don't show them.

    Breakdown of debug:
    * For EVERY sign found, it shows the title (first line)
    * If the first line equals train, !train, +train, cart, !cart or +cart, it sets the same title but with brackets under the titleNew variable. It also outputs the titleNew variable.
    * After that, it shows the player the ----- line, so it's clear when one sign has finished.

    Now, let's take a look at (part of) the debug:
    [​IMG]

    As clearly shown, somehow all the lines still have the square brackets around them, meaning it doesn't equals train, !train, +train, cart, !cart or +cart, meaning it goes straight to the ----- line.

    So... Somehow the server thinks all signs are like this, but not updated...

    Code:java
    1.  
    2. public void fixsigns(Player player) {
    3. Bukkit.broadcastMessage(ChatColor.RED + "WARNING! Lag incoming for a few seconds. Please stay calm.");
    4. player.sendMessage("TC Signfixer started.");
    5. List<BlockState> signs = new ArrayList<BlockState>();
    6. Location pos1 = new Location(Bukkit.getWorld("themecraft"), -381.0D, 4.0D, 479.0D);
    7. Location pos2 = new Location(Bukkit.getWorld("themecraft"), 468.0D, 131.0D, -679.0D);
    8.  
    9. pos1.setX(Math.floor(pos1.getX()));
    10. pos1.setY(Math.floor(pos1.getY()));
    11. pos1.setZ(Math.floor(pos1.getZ()));
    12. pos2.setX(Math.floor(pos2.getX()));
    13. pos2.setY(Math.floor(pos2.getY()));
    14. pos2.setZ(Math.floor(pos2.getZ()));
    15. if (pos1.getWorld().equals(pos2.getWorld())) {
    16. double xMin = Math.min(pos1.getX(), pos2.getX());
    17. double yMin = Math.min(pos1.getY(), pos2.getY());
    18. double zMin = Math.min(pos1.getZ(), pos2.getZ());
    19. double xMax = Math.max(pos1.getX(), pos2.getX());
    20. double yMax = Math.max(pos1.getY(), pos2.getY());
    21. double zMax = Math.max(pos1.getZ(), pos2.getZ());
    22. for (Integer x = 0; x <= Math.abs(xMax - xMin); x = x + 1) {
    23. for (Integer y = 0; y <= Math.abs(yMax - yMin); y = y + 1) {
    24. for (Integer z = 0; z <= Math.abs(yMax - yMin); z = z + 1) {
    25. Location currentPos = new Location(pos1.getWorld(), xMin + x, yMin + y, zMin + z);
    26. if (currentPos.getBlock().getState().getType().equals(Material.SIGN) || currentPos.getBlock().getState().getType().equals(Material.SIGN_POST) || currentPos.getBlock().getState().getType().equals(Material.WALL_SIGN)) {
    27. signs.add(currentPos.getBlock().getState());
    28. }
    29. }
    30. }
    31. }
    32. }
    33.  
    34. int found = 0;
    35. for (BlockState state : signs) {
    36. if (state instanceof Sign) {
    37. Sign sign = (Sign)state;
    38.  
    39. String title = sign.getLine(0);
    40. String titleNew = title;
    41. player.sendMessage(title);
    42. if (title.equalsIgnoreCase("train")) {
    43. titleNew = "[train]";
    44. player.sendMessage(titleNew);
    45. } else if (title.equalsIgnoreCase("!train")) {
    46. titleNew = "[!train]";
    47. player.sendMessage(titleNew);
    48. } else if (title.equalsIgnoreCase("+train")) {
    49. titleNew = "[+train]";
    50. player.sendMessage(titleNew);
    51. } else if (title.equalsIgnoreCase("cart")) {
    52. titleNew = "[cart]";
    53. player.sendMessage(titleNew);
    54. } else if (title.equalsIgnoreCase("!cart")) {
    55. titleNew = "[!cart]";
    56. player.sendMessage(titleNew);
    57. } else if (title.equalsIgnoreCase("+cart")) {
    58. titleNew = "[+cart]";
    59. player.sendMessage(titleNew);
    60. }
    61. player.sendMessage("-----");
    62.  
    63. sign.setLine(0, titleNew);
    64. sign.update();
    65.  
    66. found++;
    67. }
    68. }
    69. player.sendMessage("TC Signfixer finished. Total signs found in world: " + found + ".");
    70. }
    71.  
     
  9. Try sign.update(true)
    And your for-loop is messed up because
    1. z of pos1 is bigger than z of pos2
    2. Material.SIGN is the item. Check if (blockstate instanceof Sign) { like you did later in your code
     
  10. Offline

    rcth

    Sweet! The problem really was that I used y values in the z for-loop. That messed stuff up.

    Now I just need to smaller the area, because this area was way too huge. A smaller area did work!

    EDIT: Long live Worldedit implementation! Just select an area with the WE wand and voila, the fix will be applied to that area.
     
    Last edited: Sep 20, 2015
Thread Status:
Not open for further replies.

Share This Page