Solved Save blocks temporary

Discussion in 'Plugin Development' started by Bikkel007, Aug 31, 2014.

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

    Bikkel007

    Hey guys,

    I want to save broken blocks temporary and redo the changes when a game ends. I have the following HashMap to save the blocks:

    Code:
    public Map<Location, Material> changedBlocks = new HashMap<Location, Material>();
    changedBlocks.put(event.getBlock().getLocation(), event.getBlock().getType());
     
    //Resetting the blocks
    for (Entry<Location, Material> entry : changedBlocks.entrySet()) {
                Location loc = entry.getKey();
                Material mat = entry.getValue();
                loc.getBlock().setType(mat);
            }
     
    
    The problem with Material is that if I break a yellow wool block it will replace the block with a white wool block. What should I use instead?
     
  2. Offline

    Ivan

    Do the same but now just store the data in a seperate hashmap ;)
     
  3. Offline

    xMakerx

    Bikkel007

    Try just saving the block?
    Code:java
    1. public List<Block> blocks = new ArrayList<Block>();
    2. blocks.add(event.getBlock());
    3.  
    4. // Resetting the blocks
    5. for(int i = 0; i < blocks.size(); i++) {
    6. Block block = blocks.get(i);
    7. Location loc = block.getLocation();
    8. loc.getBlock().setType(block.getType());
    9. blocks.remove(block);
    10. }
     
  4. Offline

    Bikkel007

    I've tried that but that didn't work... The block doesn't change.

    I'll try that ;)
     
  5. Offline

    Gater12

    Bikkel007
    Save the block's state in a List or Set then when the game ends, loop through the List or set and update the BlockState.
     
  6. Offline

    BillyGalbreath

    In your current code:
    Code:java
    1. public Map<Location, SavedBlock> changedBlocks = new HashMap<Location, SavedBlock>();
    2. //Resetting the blocks
    3. for (Entry<Location, SavedBlock> entry : changedBlocks.entrySet()) {
    4. Location loc = entry.getKey();
    5. SavedBlock sb = entry.getValue();
    6. loc.getBlock().setType(sb.getMaterial());
    7. loc.getBlock().setData(sb.getData());
    8. }


    In a new custom class:
    Code:java
    1. public class SavedBlock {
    2. private Material material;
    3. private byte data;
    4.  
    5. public SavedBlock(Material material, byte data) {
    6. this.material = material;
    7. this.data = data;
    8. }
    9.  
    10. public Material getMaterial() {
    11. return material;
    12. }
    13.  
    14. public byte getData() {
    15. return data;
    16. }
    17. }


    Whereever you are saving the blocks upon break you just do something like this:

    Code:java
    1. changedBlocks.put(block.getLocation(), new SavedBlock(block.getType(), block.getData()));


    OOP FTW \o/
     
    Bikkel007 likes this.
  7. Offline

    xMakerx

    Bikkel007
    Try updating the code to this:
    Code:
    public List<Block> blocks = new ArrayList<Block>();
    blocks.add(event.getBlock());
     
    // Resetting the blocks
    for(int i = 0; i < blocks.size(); i++) {
    Block block = blocks.get(i);
    Location loc = block.getLocation();
    loc.getBlock().setType(block.getType());
    loc.getBlock().setData(block.getData());
    blocks.remove(block);
    }
    Saving this as a List is much easier than using a HashMap. Plus, with my way of doing it, you just need to save one thing, a Block.
     
  8. Offline

    Gater12

    Yes it will.
     
  9. Offline

    xMakerx

    Gater12

    Yeah, you're right. I forgot that in my example that I was saving the list to a yaml file, that's why it persisted. Sorry.
     
  10. Offline

    BillyGalbreath

    I think you are confused about a few things here.

    First, a List is an Object in memory same as a HashMap. Unless those Objects are saved to the disk (in a config) they are both lost in a server restart, same as everything else in memory.

    Second, a Block isn't what you seem to think it is. It's not a tangable Object. Its a placeholder. Think of your world as a 3D grid of Blocks. Each and every one of them is always there, and cannot be moved. However, you can change their properties (BlockState: a.k.a. material, data, etc) and make them look and behave differently. While you can save a BlockState to the original HashMap, it's not advised as it contains a lot more information that what is needed and could easily build up more allocated RAM than desired in this use-case.

    The easiest and most effective method is what I posted above. Save the two things you need (material and data) to a new Object, and store that Object into the existing HashMap with the Location as it's key. Simple.
     
  11. Offline

    Bikkel007

    Thanks a lot! Very neat ;) Creating my own classes always scared me, haha. But you're showing it ain't hard at all, thanks ;)

    all, thanks for your replies. It's fixed!

    BillyGalbreath
    I have got a question for you, since it looks like you know a lot! Deprecated methods are something I prefer not to use, but sometimes there is no other way right? Like the getData() from a block or to get an online player from a command so getPlayer(string).

    I was told that deprecated methods are that way to warn programmers that they will change in the near future, but doesn't it also mean that they want to warn you that there are (maybe) better ways to achieve the same things like getting a player by it's UUID?

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 10, 2016
    BillyGalbreath likes this.
  12. Offline

    BillyGalbreath

    The deprecated getData() is because of Magic Numbers. There is no alternative to it yet, so its still acceptable for use.

    The player by String has already been replaced by UUID and is strongly advised to go the UUID route (its waaay faster than using Strings now, on purpose).

    Edit: If you are temporarily storing Player data, then just store the Player object. It will not create any memory leaks like the famous rumor flying around, as long as you remove the Player object when the player quits.
     
    Bikkel007 likes this.
  13. Offline

    Bikkel007

    BillyGalbreath
    Okay thanks for the information. About getting a player from a strings, there isn't another way to get a player from a command, is there? If want to send a message to a specific player with a command, the only way to get that player is from that string right?
     
  14. Offline

    BillyGalbreath

    Correct.
     
  15. Offline

    xMakerx

    BillyGalbreath

    Wouldn't that mean saving the block(s) into a List, would be a placeholder of the block information?
     
  16. Offline

    BillyGalbreath

    Analogy time.

    Think of a grocery store with its isles and junk on its shelves. Lets say you, the store owner, decide you want to track what people are taking off your shelves so you can put the stuff back later. With your logic, you are logging the shelfs. The placeholders. Ok, so you have some shelves and you know where they are. Great. End of the day comes and you go back to those locations to check. Yup, the shelves are still there. Nothing to do. Job well done.

    With keeping track of a placeholder (a Block) you are not tracking it's contents (a BlockState).

    Point is, a Block is a Block is a Block is a Block. It's whats inside that matters.

    Edit:

    I'll go ahead and do you one better (in case the analogy doesnt make sense):
    Here's your code, explained.

    Lets keep a list of the Block.
    Code:
    public List<Block> blocks = new ArrayList<Block>();
    Good. Now lets add a Block to that list we want to track.
    Code:
    blocks.add(event.getBlock());
    Ok, time to check the list of Blocks and reset them
    Code:
    for(int i = 0; i < blocks.size(); i++) {
    Here's one of our Blocks we were tracking
    Code:
    Block block = blocks.get(i);
    Here's the location of that Block
    Code:
    Location loc = block.getLocation();
    We're going to set the Type of that Block, to the Type of that Block (which does absolutely nothing)
    Code:
    loc.getBlock().setType(block.getType());
    We'll go ahead and do the same thing with the Block data, too. This does absolutely nothing.
    Code:
    loc.getBlock().setData(block.getData());
    Now that we've done that, lets remove the block from our tracking list.
    Code:
    blocks.remove(block);
    Close the for loop here.
    Code:
    }
    Now, to clarify for the type and data setting lines above:

    You track a Block because a user breaks it. Let's say its stone, for this example. So you have a Block of Stone in the List, the user breaks it and now its air.

    Later, when you loop through your list you get the Block and set it's type to it's type. Here's where you miss the point. You are setting Air on the Block because it's current type is already Air. Thus, it does absolutely nothing.
     
  17. Offline

    JBoss925

    Block is an interface, not a class. Meaning it doesn't contain the values, it just tells where the block is. Like BillyGalbreath said, it's a placeholder, free of the values need to restore block type.
     
    BillyGalbreath likes this.
Thread Status:
Not open for further replies.

Share This Page