Solved Position relative to location

Discussion in 'Plugin Development' started by Xp10d3, Jun 16, 2022.

  1. Offline

    Xp10d3

    This is sort of a continuation of https://bukkit.org/threads/pasting-an-array-of-blocks.496920/, but I want to paste the array of blocks relative to the location provided.
    Code:java
    1.  
    2. // mapData is an array of blocks
    3. for (Block block : mapData) {
    4. Location blockLoc = block.getLocation();
    5. World world = loc.getWorld();
    6. double x = loc.getBlockX() + blockLoc.getBlockX();
    7. double y = loc.getBlockY() + blockLoc.getBlockY();
    8. double z = loc.getBlockZ() + blockLoc.getBlockZ();
    9.  
    10. Location newLoc = new Location(world, x, y, z);
    11. world.getBlockAt(newLoc).setType(block.getType());
    12. }
    13.  

    However, I don't have the origin of mapData. Is there a way to place each block relative to the location provided?
     
  2. Offline

    timtower Administrator Administrator Moderator

    @Xp10d3 Get the boundary of the thing you are trying to paste, subtract the smallest position from all.
    Add your provided location.
     
  3. Offline

    CraftCreeper6

    @Xp10d3
    This problem is why I suggested to create your own custom Block class that stores the offset for you, it does all the math upfront and pasting is as easy as adding the offset to the 'provided location'.

    But nevertheless, tim's idea is good if you want to continue with how you're currently doing the mapData.
     
  4. Offline

    Xp10d3

    Wdym by the boundary?
    EDIT: ohhhh i see. okay. im confused on the smallest position part though.

    Ah. Yeah I forgot to add the offset. Dang it. The issue is that my command creates the map, but I want to store it first and save it and repaste it multiple times. I'm not quite sure how I could store the offset in that situation unfortunately.
     
  5. Offline

    CraftCreeper6

    @Xp10d3
    Do you have a repo I can look at?
    Alternatively can I see how your command works? I guess it uses the players position there, no?
     
  6. Offline

    Xp10d3

    I don't have a repository, but I can send the methods that I use. If not I can try and set one up.
    Commands:
    [removed]

    WorldMap:
    [removed]

    Helpers:
    [removed]
     
    Last edited: Jun 17, 2022
  7. Offline

    CraftCreeper6

    @Xp10d3
    So your centre most block is the players position.

    With that you can easily calculate some offsets from that centre block to the given block.

    In your getBlocks() method it should be as easy as updating your
    Code:
    Location loc = new Location(start.getWorld(), x, y, z);
    to include the offset, rather than world position.

    Calculating a Vector for the offset is fairly simple, it's just the world location of the block you are currently iterating for, minus the world location of the centre block.
     
  8. Offline

    Xp10d3

    @CraftCreeper6 Ohhhh I see. Thank you so much. So basically:
    Code:java
    1.  
    2. public ArrayList<Block> getBlocks(Block start, int radius, Location offset) {
    3. ArrayList<Block> blocks = new ArrayList<Block>();
    4. for (double x = start.getLocation().getX() - radius; x <= start.getLocation().getX() + radius; x++) {
    5. for (double y = start.getLocation().getY() - radius; y <= start.getLocation().getY() + radius; y++) {
    6. for (double z = start.getLocation().getZ() - radius; z <= start.getLocation().getZ() + radius; z++) {
    7. Location loc = new Location(start.getWorld(), x, y, z);
    8. Block block = new Block(loc, loc.getBlock(), offset);
    9. blocks.add(block);
    10. }
    11. }
    12. }
    13. return blocks;
    14. }
    15.  

    Or do you mean in my getMap method I could just replace the current location with the offset like this:
    Code:java
    1.  
    2. public ArrayList<Block> getMap(Location offset) {
    3. File file = new File(mapName + ".txt");
    4. if (!file.exists() || !file.canRead()) {
    5. return null;
    6. }
    7. ArrayList<Block> list = new ArrayList<>();
    8. try {
    9. Scanner reader = new Scanner(file);
    10. while (reader.hasNextLine()) {
    11. String data = reader.nextLine();
    12. String[] split = data.split(", ");
    13. double x = 0;
    14. double y = 0;
    15. double z = 0;
    16. String type = "";
    17. for (String a : split) {
    18. if (a.contains("x:")) {
    19. String[] splitX = a.split("x: ");
    20. x = Double.parseDouble(splitX[1]);
    21. }
    22. if (a.contains("y:")) {
    23. String[] splitY = a.split("y: ");
    24. y = Double.parseDouble(splitY[1]);
    25. }
    26. if (a.contains("z:")) {
    27. String[] splitZ = a.split("z: ");
    28. z = Double.parseDouble(splitZ[1]);
    29. }
    30. if (a.contains("type:")) {
    31. String[] splitType = a.split("type: ");
    32. type = splitType[1].split(" }")[0];
    33. }
    34. }
    35. World world = Bukkit.getWorld(mapName);
    36. Location loc = new Location(world, x, y, z);
    37. // do some math that sets location to be offset from offset
    38. loc = offset; // i'm not sure what the math would be lol
    39. Block block = new Block(loc, type);
    40. list.add(block);
    41. }
    42. reader.close();
    43. return list;
    44. } catch (FileNotFoundException e) {
    45. System.out.println("An error occurred.");
    46. e.printStackTrace();
    47. return null;
    48. }
    49. }
    50.  
     
  9. Offline

    CraftCreeper6

    @Xp10d3
    The first is more accurate to what I'm getting it but it's not quite right.
    Code:
    public ArrayList<Block> getBlocks(Block start, int radius, Location offset) {
         ArrayList<Block> blocks = new ArrayList<Block>();
         for (double x = start.getLocation().getX() - radius; x <= start.getLocation().getX() + radius; x++) {
           for (double y = start.getLocation().getY() - radius; y <= start.getLocation().getY() + radius; y++) {
             for (double z = start.getLocation().getZ() - radius; z <= start.getLocation().getZ() + radius; z++) {
               Location loc = new Location(start.getWorld(), x, y, z);
               Block block = new Block(loc, loc.getBlock(), offset);
               blocks.add(block);
             }
          }
         }
      return blocks;
      }
    The parts in bold are the bits that need changing.
    In fact, the parameter for offset can be entirely removed.

    The part that needs updating is the loc variable.
    Instead of storing the world location there (which is what you are currently storing), you need the offset.

    So previously I stated that you can calculate an offset by taking the current block you are iterating over, and subtracting the centre block ('start' in your case).

    (pseudo)
    Code:
    public ArrayList<Block> getBlocks(Block start, int radius) {
         ArrayList<Block> blocks = new ArrayList<Block>();
         for (double x = start.getLocation().getX() - radius; x <= start.getLocation().getX() + radius; x++) {
           for (double y = start.getLocation().getY() - radius; y <= start.getLocation().getY() + radius; y++) {
             for (double z = start.getLocation().getZ() - radius; z <= start.getLocation().getZ() + radius; z++) {
               Location blockLocation = new Location(start.getWorld(), x, y, z);
    
               Location offset = 'blockLocation' subtract 'start'
    
               Block block = new Block(offset, loc.getBlock());
               blocks.add(block);
             }
          }
         }
      return blocks;
      }
     
  10. Offline

    Xp10d3

    @CraftCreeper6 Ah I see. Thank you! So then I won't really have to update the text file for the entire map. I'll try the code out and see how it works.
    EDIT: Actually, in my case the main issue lies in createMap since that's where the placing blocks issue is. I updated the code for it to match what you mentioned:
    Code:java
    1.  
    2. public void createMap(Location loc) {
    3. for (Block block : mapData) {
    4. Location blockLoc = block.getLocation();
    5. World world = loc.getWorld();
    6. double x = blockLoc.getBlockX() - loc.getBlockX();
    7. double y = blockLoc.getBlockY() - loc.getBlockY();
    8. double z = blockLoc.getBlockZ() - loc.getBlockZ();
    9.  
    10. Location newLoc = new Location(world, x, y, z);
    11. world.getBlockAt(newLoc).setType(block.getType());
    12. }
    13. }
    14.  

    I'll test it out rq
     
  11. Offline

    CraftCreeper6

    @Xp10d3
    For replacing the map you need to add the offset to the 'loc' variable. Which it looks like you have done, though it's hard to tell given that I don't know what the Block class looks like :D
     
  12. Offline

    Xp10d3

    @CraftCreeper6 OOPS I forgot to put the block class.
    https://sourceb.in/95EUjX37B1

    I updated the createMap method but it still doesn't seem to work unfortunately.
    Code:java
    1.  
    2. public void createMap(Location loc, ArrayList<Block> mapData) {
    3. for (Block block : mapData) {
    4. Location blockLoc = block.getLocation();
    5. World world = loc.getWorld();
    6.  
    7. double x = blockLoc.getBlockX() - loc.getBlockX();
    8. double y = blockLoc.getBlockY() - loc.getBlockY();
    9. double z = blockLoc.getBlockZ() - loc.getBlockZ();
    10.  
    11. Location newLoc = new Location(world, x, y, z);
    12. world.getBlockAt(newLoc).setType(block.getType());
    13. this.log(newLoc.toString());
    14. }
    15. }
    16.  

    But yea I'll try adding instead of subtracting this time :)
     
  13. Offline

    CraftCreeper6

    @Xp10d3
    What does your getBlocks method look like now? That's where the magic happens.
     
  14. Offline

    Xp10d3

    @CraftCreeper6
    Code:java
    1.  
    2. public ArrayList<Block> getBlocks(Block start, int radius) {
    3. ArrayList<Block> blocks = new ArrayList<Block>();
    4. for (double x = start.getLocation().getX() - radius; x <= start.getLocation().getX() + radius; x++) {
    5. for (double y = start.getLocation().getY() - radius; y <= start.getLocation().getY() + radius; y++) {
    6. for (double z = start.getLocation().getZ() - radius; z <= start.getLocation().getZ() + radius; z++) {
    7. Location loc = new Location(start.getWorld(), x, y, z);
    8. Block block = new Block(loc, loc.getBlock());
    9. blocks.add(block);
    10. }
    11. }
    12. }
    13. return blocks;
    14. }
    15.  

    This is how it stores the map itself. The getBlocks location shouldn't really matter since I'm creating the map it different places. I could be wrong though :D
     
  15. Offline

    CraftCreeper6

    @Xp10d3
    The getBlocks method will be more important than any other, since it's what will create the offset to begin with.

    Re-read this:
    And try to implement it.
     
    Xp10d3 likes this.
  16. Offline

    Xp10d3

    @CraftCreeper6 What if I want to change the offset? I guess what I'm saying is that the offset changes for each map. I provide the offset when creating the map if that makes sense.

    1. Create a new map with a text file. I get the blocks and store it in the text file.
    2. If I want to paste a map, I provide a new location where the map will be created (this is the offset in a sense).

    Sorry I might not make any sense. I'll try changing the getBlocks method again.
     
  17. Offline

    CraftCreeper6

    @Xp10d3
    When you create a map you are looping over all the blocks surrounding a given player.
    When you save those blocks you don't want the world position, that wouldn't make any sense since you most likely won't want to spawn that map in the same place it was created, you want it to be more of a schematic.
    So instead of storing the world position, just store the difference between the players position and the block that you are looping over, this will be your offset for each block.
    When it comes to spawning the block, all you'd have to do is get the centre location of where you want the map to be, and add the offset value for each block so that it will spawn relative to the chosen location, rather than where you originally created the map.
    [​IMG]
    Imagine that the player is the red dot, the one of the blocks you want to save is the orange dot, and the blue dot is the world centre.

    You don't want to store the difference between the blue dot and the orange dot, which is what the world position is, because when you try to spawn the block it's just going to be in the same place it was when you originally copied it.

    Instead you want the difference between the red dot and the orange dot, the offset.
    Now, even if you player moves somewhere, you'll be able to spawn that same block by just adding the player position and the offset together, giving you a new location in space.
     
    Xp10d3 likes this.
  18. Offline

    Xp10d3

    Ah I see. So basically the getBlocks method gets the offset of each block so that when spawning in the block, all I have to do is get the offset and compare it with the location of the current player? So for example:
    Code:java
    1.  
    2. public ArrayList<Block> getBlocks(Block start, int radius) {
    3. ArrayList<Block> blocks = new ArrayList<Block>();
    4. for (double x = start.getLocation().getX() - radius; x <= start.getLocation().getX() + radius; x++) {
    5. for (double y = start.getLocation().getY() - radius; y <= start.getLocation().getY() + radius; y++) {
    6. for (double z = start.getLocation().getZ() - radius; z <= start.getLocation().getZ() + radius; z++) {
    7. Location blockLocation = new Location(start.getWorld(), x, y, z);
    8. Location loc = blockLocation.subtract(start.getLocation());
    9. Block block = new Block(loc, loc.getBlock());
    10. blocks.add(block);
    11. }
    12. }
    13. }
    14. return blocks;
    15. }
    16.  

    Then when spawning in the map:
    Code:java
    1.  
    2. public void createMap(Location loc, ArrayList<Block> mapData) {
    3. for (Block block : mapData) {
    4. Location blockLoc = block.getLocation();
    5. World world = loc.getWorld();
    6.  
    7. Location newLoc = blockLoc.subtract(loc);
    8. world.getBlockAt(newLoc).setType(block.getType());
    9. this.log(newLoc.toString());
    10. }
    11. }
    12.  

    Hopefully I'm understanding everything correctly :D Thank you for the explanation that's super helpful!
     
  19. Offline

    CraftCreeper6

    @Xp10d3
    Close, when you spawn the blocks you want to add, not subtract.

    EDIT: Oh also, make sure that in getBlocks you are using the blockLocation when you call getBlock() and not the new location, since the new location is just an offset.
     
    Xp10d3 likes this.
  20. Offline

    Xp10d3

    @CraftCreeper6 Ahh thank you! Unfortunately it doesn't seem to be working... This is what I have right now:
    createMap
    Code:java
    1.  
    2. public void createMap(Location loc, ArrayList<Block> mapData) {
    3. for (Block block : mapData) {
    4. Location blockLoc = block.getLocation();
    5. World world = loc.getWorld();
    6.  
    7. Location newLoc = blockLoc.add(loc);
    8. world.getBlockAt(newLoc).setType(block.getType());
    9. if (block.getType().toString() != "AIR") {
    10. this.log("Placing " + block.getType() + " at x: " + newLoc.getBlockX() + " y: " + newLoc.getBlockY() + " z: " + newLoc.getBlockZ());
    11. }
    12. }
    13. }
    14.  

    getBlocks
    Code:java
    1.  
    2. public ArrayList<Block> getBlocks(Block start, int radius) {
    3. ArrayList<Block> blocks = new ArrayList<Block>();
    4. for (double x = start.getLocation().getX() - radius; x <= start.getLocation().getX() + radius; x++) {
    5. for (double y = start.getLocation().getY() - radius; y <= start.getLocation().getY() + radius; y++) {
    6. for (double z = start.getLocation().getZ() - radius; z <= start.getLocation().getZ() + radius; z++) {
    7. Location blockLocation = new Location(start.getWorld(), x, y, z);
    8. Location loc = blockLocation.subtract(start.getLocation());
    9. Block block = new Block(loc, blockLocation.getBlock());
    10. blocks.add(block);
    11. }
    12. }
    13. }
    14. return blocks;
    15. }
    16.  


    This is what's logged (with omitting any block that is AIR):
    https://sourceb.in/zDC8yBlf4h

    This is what happens when I use /createmap Urban2
    upload_2022-6-17_15-47-21.png

    This is the position I'm at when I execute the command along with the original map. The blocks aren't placed correctly, nor is the actual map created at the right location unfortunately.
    upload_2022-6-17_15-47-31.png
     
  21. Offline

    CraftCreeper6

    @Xp10d3
    Make sure to run /setmap before you create it, I don't see that in your logging.
     
  22. Offline

    Xp10d3

  23. Offline

    CraftCreeper6

    @Xp10d3
    When you run createMap, instead of debugging where it was placed, could you debug the offset?
     
  24. Offline

    Xp10d3

  25. Offline

    CraftCreeper6

    @Xp10d3
    And are they correct, is there a block 67 blocks on the x, 103 on the y and 51 on the z from the players position?
     
  26. Offline

    Xp10d3

    There is yes. The locations are logged correctly, but the position is incorrect and the map itself isn't pasted correctly... I guess I'm kinda stumped on what to do next haha
     
  27. Offline

    CraftCreeper6

    @Xp10d3
    Okay, try this, (good idea to back up your world too)
    run the setmap command and stay still, what happens if you then run the createmap command from the same location? Does it place all the blocks in the right locations?
     
    Xp10d3 likes this.
  28. Offline

    Xp10d3

    Interesting... It deletes the main world. So I guess it works, but it doesn't save the correct type/location.
    upload_2022-6-17_16-5-3.png
     
  29. Offline

    CraftCreeper6

    @Xp10d3
    Ahh, my bad.

    In getBlocks change
    Code:
    Location loc = blockLocation.subtract(start.getLocation());
    to
    Code:
    Location loc = start.getLocation().subtract(blockLocation);
    (probably)
     
  30. Offline

    Xp10d3

    Unfortunately that makes everything air. The location is static.
    Code:java
    1.  
    2. Location blockLocation = new Location(start.getWorld(), x, y, z);
    3. Location loc = start.getLocation().subtract(blockLocation);
    4. Block block = new Block(loc, blockLocation.getBlock());
    5.  


    Code:
    { x: -420274.0, y: -66.0, z: -20.0, type: AIR, world: Urban }
    { x: -420274.0, y: -66.0, z: -20.0, type: AIR, world: Urban }
    { x: -420274.0, y: -66.0, z: -20.0, type: AIR, world: Urban }
    { x: -420274.0, y: -66.0, z: -20.0, type: AIR, world: Urban }
    { x: -420274.0, y: -66.0, z: -20.0, type: AIR, world: Urban }
    { x: -420274.0, y: -66.0, z: -20.0, type: AIR, world: Urban }
    { x: -420274.0, y: -66.0, z: -20.0, type: AIR, world: Urban }
    { x: -420274.0, y: -66.0, z: -20.0, type: AIR, world: Urban }
    { x: -420274.0, y: -66.0, z: -20.0, type: AIR, world: Urban }
    { x: -420274.0, y: -66.0, z: -20.0, type: AIR, world: Urban }
    { x: -420274.0, y: -66.0, z: -20.0, type: AIR, world: Urban }
    { x: -420274.0, y: -66.0, z: -20.0, type: AIR, world: Urban }
    { x: -420274.0, y: -66.0, z: -20.0, type: AIR, world: Urban }
    { x: -420274.0, y: -66.0, z: -20.0, type: AIR, world: Urban }
    { x: -420274.0, y: -66.0, z: -20.0, type: AIR, world: Urban }
    { x: -420274.0, y: -66.0, z: -20.0, type: AIR, world: Urban }
    { x: -420274.0, y: -66.0, z: -20.0, type: AIR, world: Urban }
    
     

Share This Page