Solved "Pasting" an array of blocks

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

  1. Offline

    Xp10d3

    Hello! It's been a hot minute since I've posted here, but recently I've been getting into Bukkit development again and want to "paste" an array of blocks similar to WorldEdit. Essentially, I have a command that gets all blocks within a radius specified. Now, I want to paste the blocks starting in a given location. This is what the /setMap command looks like:
    Code:java
    1.  
    2. Set<Block> sphere = helper.sphereAround(player.getLocation(), radius);
    3. List<Block> list = new ArrayList<Block>();
    4. list.addAll(sphere);
    5. for (int i = 0; i < list.size(); i++) {
    6. helper.log(prefix + list.get(i));
    7. }
    8.  

    And this is what I want my createMap() method to look like:
    Code:java
    1.  
    2. // mapData is an array list of blocks
    3. public void createMap(Location origin) {
    4. for (Block block : mapData) {
    5. block.setType(block.getType());
    6. }
    7. }
    8.  


    I'm attempting to set the array of blocks to be pasted at the origin specified. How can I accomplish this?
     
  2. Offline

    CraftCreeper6

    @Xp10d3
    Since you can't set the location of a Block, it may be best to create your own 'Block' style class that takes 'BlockInfo' and a customised 'Location' esque class that you can use.

    When you create your map you'll want to store the offset of the block from the player and use that when you spawn them back in.

    That's not the best explanation and I can definitely see how it could be confusing so here's ish what I mean.
    Code:
    BlockInfo
    {
        Material type
        some other data...
    }
    
    Code:
    MyBlockClass
    {
        BlockInfo someBlockToCopy
        Location offsetFromPlayer
    }
    
    When you create your map, instead of using only the Block (which has Location baked into it), create a new instance of your MyBlockClass and set the values for BlockInfo and Location, the location being the offset from the player and not the real world location of the block.

    Then when it comes to creating the map, take the players 'origin' and simply add the offsets for each block and use world#setType() or some other variation of changing a Block to create the map at the given offset.

    Worth noting that if your map is large then it'll cause a considerable amount of lag, so consider having creating a queue style system that works in chunks rather than pasting the whole schematic at once.
     
  3. Offline

    Xp10d3

    Thank you! I'm now onto the last part of my problem. I store the block as a string in a text file, but want to read it to paste the blocks. However, I'm not sure how to convert a string to a block. Ex.
    Code:java
    1.  
    2. public void readFromMap(String mapName) {
    3. try {
    4. File map = new File(mapName + ".txt");
    5. if (map.canRead()) {
    6. Scanner reader = new Scanner(map);
    7. while (reader.hasNextLine()) {
    8. String data = reader.nextLine();
    9. Block block = data; // doesn't work
    10. }
    11. reader.close();
    12. } else {
    13.  
    14. }
    15. } catch (IOException e) {
    16. e.printStackTrace();
    17. }
    18. }
    19.  
     
  4. Offline

    CraftCreeper6

    You can't just do it like that unfortunately. JSON is usually pretty good at doing that sort of stuff if you're interested. Alternatively, just use Bukkits configs.

    In the implementation I suggested above you won't want to use the Block class anymore like discussed.

    Best plan of action, create your own serialize and deserialize methods for your custom block class and use those to convert to and from strings / ConfigurationSections / JSON, whatever you end up using.

    Sent from my LE2123 using Tapatalk
     
  5. Offline

    Xp10d3

    Ahh okay. So basically something like:
    Code:java
    1.  
    2. public class Block {
    3. private org.bukkit.block.Block block;
    4. private Location offset;
    5. public Block(Location offset, org.bukkit.block.Block block) {
    6. this.block = block;
    7. this.offset = offset;
    8. }
    9.  
    10. public Location getLocation() {
    11. return block.getLocation();
    12. }
    13.  
    14. public Material getType() {
    15. return block.getType();
    16. }
    17.  
    18. public World getWorld() {
    19. return this.getLocation().getWorld();
    20. }
    21.  
    22. public String toString() {
    23. double x = offset.getBlockX();
    24. double y = offset.getY();
    25. double z = offset.getZ();
    26. Material type = block.getType();
    27. return "{ x: " + x + ", y: " + y + ", z: " + z + ", type: " + type + ", world: " + block.getWorld().getName() + " }";
    28. }
    29. }
    30.  

    The one issue is figuring out how to get the block based on it's type...
     
    Last edited: Jun 15, 2022
  6. Offline

    CraftCreeper6

    @Xp10d3
    Yes that works in terms of your toString method.

    I would avoid having the same class name as the base Block class since it'll get pretty confusing later on, especially if you have two imports with the same class. Though of course your free to keep it like that.

    As for your block variable in your Block class, I originally said to have a BlockInfo class that almost emulates a Block since I'm not entirely sure if a Block is just a reference to a realworld block or if it's just an instance copy of it. You're free to test that yourself, place a block, save it to a config, change the block, and paste the config values, if the block still uses your saved type then whoopie, all good, if not, it's an issue with that Block class.

    Getting a block based on its type should be fairly easy. There are definitely optimisations that you could be doing to make this process simpler but for the sake of getting something working you just need to iterate over all Block's in your block list and get its type. Check against your desired type and voilà.
     
  7. Offline

    DopeBrot

    maybe add in the data of a block
     
  8. Offline

    Xp10d3

    @CraftCreeper6 Okay! Thank you. That’s super helpful. Yeah, I removed the Block type since it ended up making things frustrating if I couldn’t pass it as a parameter, so I just ended up storing the type instead. As for what @DopeBrot said, that’s all I have to do now haha. Thanks everyone for your help!
     
    DopeBrot likes this.

Share This Page