What is most Efficient way to store block.locations?

Discussion in 'Plugin Development' started by iZanax, Nov 13, 2012.

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

    iZanax

    What I try to accomplish is to have breakable Glass blocks and panes,
    But these locations have to be saved, because after x time or when some method is called.
    These locations has to being reset, and place there a glass block or glass plane.
    But what is an efficient way to store the locations of the broken glass?
     
  2. Offline

    LukeSFT

    as a hashmap?
     
  3. Offline

    fireblast709

    I would go for:
    • HashMap if a server restart would clean the list
    • YAML if after a restart it should still have the list
    Keep in mind that both these can become very big. So it solely depends on how many blocks you think that are broken
     
  4. Offline

    iZanax

    I thought Player and Locations are not safe to save?
    But if Locations are, I could use that, if it efficient on big scale.
     
  5. Offline

    fireblast709

    I do not know about players, use their names for that. For Locations I would say .clone() them, as Java passes on by reference here, and we all know pistons are good with moving blocks :3 (just to be on the safe side)
     
  6. Offline

    Comphenix

    Cloning them won't help much.

    The problem with storing Location is that it keeps a reference to the parent world object, and as a result, will prevent the garbage collector from cleaning up if the world is unloaded.

    So, you either have to use a class that's safe to store (BlockVector) or use weak references. Since you mentioned a timeout, I suppose you could Google Guava (included in CraftBukkit) to do most of the work (download):
    Code:java
    1. public class TemporaryModifcations extends JavaPlugin implements Listener {
    2.  
    3. public static int TICKS_PER_SECOND = 20;
    4.  
    5. private static class BlockData {
    6. private WeakReference<World> worldReference;
    7. private int typeID;
    8. private byte data;
    9.  
    10. public BlockData(Block block) {
    11. this.worldReference = new WeakReference<World>(block.getWorld());
    12. this.typeID = block.getTypeId();
    13. this.data = block.getData();
    14. }
    15.  
    16. /**
    17.   * Restore the current block.
    18.   * @return TRUE if the block was restored, FALSE otherwise.
    19.   */
    20. public boolean restore(BlockVector vector) {
    21. if (getWorld() != null) {
    22. Block block = getWorld().getBlockAt(vector.toLocation(getWorld()));
    23.  
    24. // Restore type and data
    25. block.setTypeId(typeID);
    26. block.setData(data);
    27. return true;
    28. } else {
    29. return false;
    30. }
    31. }
    32.  
    33. public World getWorld() {
    34. return worldReference.get();
    35. }
    36. }
    37.  
    38. private Cache<BlockVector, BlockData> restoreQueue;
    39.  
    40. @Override
    41. public void onLoad() {
    42. restoreQueue = CacheBuilder.
    43. newBuilder().
    44. concurrencyLevel(2).
    45. weakValues().
    46. expireAfterWrite(10, TimeUnit.SECONDS).
    47. removalListener(new RemovalListener<BlockVector, BlockData>() {
    48. @Override
    49. public void onRemoval(RemovalNotification<BlockVector, BlockData> entry) {
    50. entry.getValue().restore(entry.getKey());
    51. }
    52. }).
    53. build(new CacheLoader<BlockVector, BlockData>() {
    54. @Override
    55. public BlockData load(BlockVector arg0) throws Exception {
    56. throw new RuntimeException("Unsupported! Cannot generate entries, must be placed manually.");
    57. }
    58. });
    59. }
    60.  
    61. @Override
    62. public void onEnable() {
    63. PluginManager manager = getServer().getPluginManager();
    64. manager.registerEvents(this, this);
    65.  
    66. // Run the block cleanup once per second
    67. getServer().getScheduler().scheduleSyncRepeatingTask(this, new Runnable() {
    68. @Override
    69. public void run() {
    70. restoreQueue.cleanUp();
    71. }
    72. }, TICKS_PER_SECOND, TICKS_PER_SECOND);
    73. }
    74.  
    75. @EventHandler
    76. public void onBlockBreakEvent(BlockBreakEvent event) {
    77. BlockData data = new BlockData(event.getBlock());
    78. BlockVector vector = new BlockVector(event.getBlock().getLocation().toVector());
    79.  
    80. // Expire after two minutes
    81. restoreQueue.asMap().put(vector, data);
    82. }
    83. }
     
  7. Offline

    iZanax

    Thanks a lot Comphenix

    I've one last question,
    because it u got the knowledge how some things get garbage collected.
    I've a problem with shooting snowballs.
    I use:
    PHP:
            Snowball snowball player.getWorld().spawn(player.getEyeLocation(), Snowball.class);
    But the problem is that the snowballs that are shooted in a direction that isn't loaded get's stuck and not removed.
    The problem is so bad, that after 5minutes the entity counter goes to 5-10k each 5 minutes.
    I use now a entity remover plugin, but this should not be the solution.
    Is this a problem of bukkit? that projectiles don't get removed when its reaches an unloaded chunk?
    Or is there an other way to remove these projectiles, because we had spikes of 50-100k entities...
    And that drains the RAM like crazy. Thanks a lot for advice.
     
  8. Offline

    ZeusAllMighty11


    Player can be saved as a string, using the getName() method.
    Locations can be serialized.
     
  9. Offline

    TwistedMexi

    *must be serialized before they can be saved iirc. There's custom methods out there to do so - or if you just need to compare, you can save the world+getX, getY, getZ to a string.
     
Thread Status:
Not open for further replies.

Share This Page