Solved Diagonals

Discussion in 'Plugin Development' started by Butter1484, Mar 28, 2016.

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

    Butter1484

    This is a problem I've posted about before and was unable to get a solution to. This time, I thought that I would attach some screenshots to try and illustrate what I am trying to do. Basically, I am trying to change the color of wool along the diagonal of the region between two locations. Here are the screenshots of the sort of thing I am trying to do. I don't need the code to change the wool, I already have that down, just the logic needed to only do the diagonal

    2016-03-28_23.31.44.png 2016-03-28_23.33.23.png 2016-03-28_23.34.44.png 2016-03-28_23.35.11.png
     
  2. Offline

    bijx

    That problem needs a little brainpower to do effectively because if you wanted to use if statements, it would be a mess. Though if it comes down to it, I think selection may be the way to go.

    For example, for the last image, you could check to see whether the length of the selection is equal to the width of the selection (if the number of blocks in on the x-axis and z-axis), then the fourth scenario holds true and you use the code to change the wool in that specific step pattern.

    For the second image, I was thinking if your do a selection like this, it may work:

    if ((x2-x1)==2){
    change wool relative to scenario two;
    }
    this probably only works in the positive quadrant of the world.

    Anyways, that's my idea. Anyone else care to give an idea?
     
  3. Offline

    567legodude

    Lightspeed likes this.
  4. Offline

    blablubbabc

    Or you could use bukkit's BlockIterator, which works very similar to the algorithm mentioned above. That way you wouldn't have to re-implement that algorithm.
     
  5. Offline

    mcdorli

    BlockIterator goes trough a line of blocks according to a 3d line, you can have instances, where it doesn't work properly in this case
     
  6. Offline

    Butter1484

    So if I understand what that is saying and try and change the example they give to Java it would be something like this?
    Code:
        
         double deltax = x1 - x0;
         double deltaz = z1 - z0;
         double error = 0;
         double deltaerr = Math.abs(deltaz / deltax); 
         int z = z0;
         for (int x = x0; x <= x1; x++){
             //Code to change blocks
             error += deltaerr;
             while (error ≥ 0.5){
                 //Code to change blocks
                 z = z + sign(z1 - z0);
                 error = error - 1.0;
            }
        }
     
  7. Offline

    blablubbabc

    I don't see a problem with BlockIterator. If you use a direction vector which points towards the target block, in 2d space (meaning: y = 0), you should get the same result.
     
  8. Offline

    Butter1484

    I'm not super familiar with BlockIterator. Can you give me some example code of how I would use it in a situation like this?
     
  9. Offline

    blablubbabc

    Out of my head, not checked if correct:
    Code:
    Block startBlock = ..;
    Block endBlock = ..;
    assert startBLock != null && endBlock!= null;
    
    World world = startBlock.getWorld();
    assert world.equals(endBlock.getWorld());
    // center of start and end block:
    Vector startLoc = startBlock.getLocation().add(0.5D, 0.5D, 0.5D).toVector();
    Vector endLoc = endBlock.getLocation().add(0.5D, 0.5D, 0.5D).toVector();
    Vector direction = endLoc.clone().subtract(startLoc);
    double distance = direction.length();
    direction.normalize(); // not sure if needed
    
    BlockIterator blockIterator = new BlockIterator(world, startLoc, direction, 0.0D, Math.ceil(distance));
    while (blockIterator.hasNext()) {
        Block block = blockIterator.next();
        if (block.equals(startBlock)) continue; // ignoring start
        if (block.equals(endBlock)) break; // abort if we reach the end block
        // do something with the block in between start and end:
        block.setType(Material.WOOL);
    }
    
    As noted above: This should also work if the start and end block are at different heights. Though, I don't see a problem of using it for blocks on the same height, like in your case.
     
  10. Offline

    Butter1484

    Thanks so much! I've been stuck on this for months. This should work fine for what I'm trying to do for the most part. There is only one more thing I want it to be able to do. Basically now that I can do the diagonal I would like it to extend it up or down rather than making a 3D diagonal if the two blocks are at different heights.
     
  11. Offline

    blablubbabc

    Well, simply perform this for 2 blocks on the same height (ex. the block pair with lower height), and for every 'found block between' you additionally fill in the blocks above up to the target height.
     
  12. Offline

    Butter1484

    Umm I'm a little lost. Would help if you explain using that example you posted earlier
     
  13. Offline

    blablubbabc

    Code:
    // 2 blocks, possibly at different heights:
    Block startBlockRaw = ..;
    Block endBlockRaw = ..;
    World world = startBlockRaw.getWorld();
    int startY = startBlockRaw.getY();
    int endY = endBlockRaw.getY();
    
    int lowerY = Math.min(startY, endY);
    int upperY = Math.max(startY, endY);
    
    // 2 blocks at the same height, used for the BLockIterator stuff shown above:
    Block startBlock = world.getBlockAt(startBlockRaw.getX(), lowerY, startBlockRaw.getZ());
    Block endBlock = world.getBlockAt(endBlockRaw.getX(), lowerY, endBlockRaw.getZ());
    
    // .. inside the BlockIterator loop, when a block is found:
    block = blockIterator.next(); // the block in between startBlock and endBlock, but at height lowerY
    // do something with this block and all blocks up to the upperY:
    for (int y = lowerY; y <= upperY, y++) {
        Block someBlock = world.getBlockAt(block.getX(), y, block.getZ());
        // do something with this:
        someBlock.setType(Material.WOOL);
    }
    
    
     
  14. Offline

    Butter1484

    Ok so that's better than it was all of the ground space is colored, but it won't color the walls, just the block in the floor under the wall 2016-03-29_17.58.46.png
     
  15. Offline

    blablubbabc

    Well, I have ignored the start and endblock above in the loop of the BlockIterator. If the block in the wall is your end block, you will have to run the 2nd loop (the for-loop) for the end block as well, before breaking out of the while loop of the BlockIterator.

    In other words:
    Remove this line: if (block.equals(startBlock)) continue; // ignoring start
    And move this line to the end of the while-loop of the BlockIterator: if (block.equals(endBlock)) break; // abort if we reach the end block
     
  16. Offline

    Butter1484

    Hmm I had removed both of those lines already, and I added that second one back in where you said but it is still doing the same as it was before
     
  17. Offline

    blablubbabc

    Can you post your current code?
     
  18. Offline

    Butter1484

    For reference hitBlock is obtained from a location that an arrow hits

    Code:
                World world = player.getWorld();
    
             // 2 blocks, possibly at different heights:
                Block startBlockRaw = new Location(world, player.getLocation().getX(), player.getLocation().getY() - 1, player.getLocation().getZ()).getBlock();;
                Block endBlockRaw = hitBlock;
                int startY = startBlockRaw.getY();
                int endY = endBlockRaw.getY();
                
                int lowerY = Math.min(startY, endY);
                int upperY = Math.max(startY, endY);
                int yDiff = Math.abs(startY - endY);
             // 2 blocks at the same height, used for the BLockIterator stuff shown above:
                Block startBlock = world.getBlockAt(startBlockRaw.getX(), lowerY, startBlockRaw.getZ());
                Block endBlock = world.getBlockAt(endBlockRaw.getX(), lowerY, endBlockRaw.getZ());
                
               
               
                assert startBlock != null && endBlock!= null;
                
    
                assert world.equals(endBlock.getWorld());
                // center of start and end block:
                Vector startLoc = startBlock.getLocation().add(0.5D, 0.5D, 0.5D).toVector();
                Vector endLoc = endBlock.getLocation().add(0.5D, 0.5D, 0.5D).toVector();
                Vector direction = endLoc.clone().subtract(startLoc);
                double distance = direction.length();
                direction.normalize(); // not sure if needed
                
                BlockIterator blockIterator = new BlockIterator(world, startLoc, direction, 0.0D, (int) Math.ceil(distance));
                while (blockIterator.hasNext()) {
                    Block block = blockIterator.next();
                    for (int y = lowerY; y <= upperY; y++) {
                        Block someBlock = world.getBlockAt(block.getX(), y, block.getZ());
                        // do something with this:
                    if (block.getType() == Material.WOOL) {
                        block.setType(Material.WOOL);
                        if (GameManager.green.contains(player.getName())) {
                            block.setData(DyeColor.LIME.getData());
                        }
                        if (GameManager.purple.contains(player.getName())) {
                            block.setData(DyeColor.PURPLE.getData());
                        }
                    }
                    }
                    if (block.equals(endBlock)) break;
                }
     
  19. Offline

    blablubbabc

    2 possible issues:
    hitBlock might be the wrong block. Usually, if an arrow hits a block at that wool wall and you get the hitBlock via arrow.getLocation().getBlock(), that will give you the block in front of the wall.

    In case you already handle this correct and hitBlock is actually the block in the wall: Well, maybe add a debug print to 'if (block.equals(endBlock))' to check if this is ever the case. If it is not, you could try increasing the maxDistance parameter of the BlockIterator (the '(int) Math.ceil(distance)'-part in the constructor).
     
  20. Offline

    Butter1484

    hitBlock should be correct, it seems that the block underneath the wall is being colored.
     
  21. Offline

    blablubbabc

    Ah, I see the issue in your code:
    Code:
    if (block.getType() == Material.WOOL) {
                        block.setType(Material.WOOL);
                        if (GameManager.green.contains(player.getName())) {
                            block.setData(DyeColor.LIME.getData());
                        }
                        if (GameManager.purple.contains(player.getName())) {
                            block.setData(DyeColor.PURPLE.getData());
                        }
                    }
    Replace 'block' with 'someBlock' in the code part shown above.
    'block' is the block found by the BlockIterator (the block at the floor height).
    'someBlock' on the other hand is the block with differing height, inside the for-loop. You have to use that variable instead.
     
  22. Offline

    Butter1484

    There we go. That's as close as I think I can get to what I wanted to do. Thanks.
     
  23. Offline

    mcdorli

    @blablubbabc please don't spoonfeed, you do more harm than good
     
Thread Status:
Not open for further replies.

Share This Page