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 Set<Block> sphere = helper.sphereAround(player.getLocation(), radius);List<Block> list = new ArrayList<Block>();list.addAll(sphere);for (int i = 0; i < list.size(); i++) { helper.log(prefix + list.get(i));} And this is what I want my createMap() method to look like: Code:java // mapData is an array list of blockspublic void createMap(Location origin) { for (Block block : mapData) { block.setType(block.getType()); }} I'm attempting to set the array of blocks to be pasted at the origin specified. How can I accomplish this?
@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.
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 public void readFromMap(String mapName) { try { File map = new File(mapName + ".txt"); if (map.canRead()) { Scanner reader = new Scanner(map); while (reader.hasNextLine()) { String data = reader.nextLine(); Block block = data; // doesn't work } reader.close(); } else { } } catch (IOException e) { e.printStackTrace(); } }
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
Ahh okay. So basically something like: Code:java public class Block { private org.bukkit.block.Block block; private Location offset; public Block(Location offset, org.bukkit.block.Block block) { this.block = block; this.offset = offset; } public Location getLocation() { return block.getLocation(); } public Material getType() { return block.getType(); } public World getWorld() { return this.getLocation().getWorld(); } public String toString() { double x = offset.getBlockX(); double y = offset.getY(); double z = offset.getZ(); Material type = block.getType(); return "{ x: " + x + ", y: " + y + ", z: " + z + ", type: " + type + ", world: " + block.getWorld().getName() + " }"; }} The one issue is figuring out how to get the block based on it's type...
@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à.
@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!