[TUT] Creating a Chest Lock Addon for a Minigame

Discussion in 'Resources' started by DevRosemberg, Jan 8, 2014.

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

    DevRosemberg

    [​IMG]
    Hello Everyone and welcome to another one of my Tutorials, this time i did it with CaptainBern. In this tutorial we will be teaching you how to add a Chest Lock feature like what you may have seen in The Walls or other games which dosent let you open a chest if You havent Placed it. Or if you place one locks it depending if you still have Locks Left.

    1) Our First step is to Create the LockManager.java Class, so we will go ahead and create one and make it implement Listener:

    Code:java
    1. public class LockManager implements Listener {
    2.  
    3. }


    2) Then we will create 2 HashMaps, HashMap<String, Location> locked = new HashMap<String, Location>(); and private HashMap<String, Integer> players = new HashMap<String, Integer>();

    Code:java
    1. public class LockManager implements Listener {
    2. private HashMap<String, Integer> players = new HashMap<String, Integer>();
    3. private HashMap<String, Location> locked = new HashMap<String, Location>();
    4. }


    3) Then we will create our First Listener which will be the BlockPlaceEvent, in this Event we will add the feature to add the Block to the Locked HashMap only if the player has locks left, to do this we will use the following code:

    Code:java
    1. @EventHandler
    2. public void onBlockPlace(BlockPlaceEvent event) {
    3. Block block = event.getBlock();
    4. Player player = event.getPlayer();
    5. Integer number = players.get(player.getName());
    6. if (block.getType() != Material.CHEST || block.getType() != Material.FURNACE) {
    7. return;
    8. }
    9.  
    10. if (players.containsKey(player.getName()) && players.get(event.getPlayer()) == 2) {
    11. //Some nice messages
    12. return;
    13. }
    14.  
    15. locked.put(player.getName(), block.getLocation());
    16. players.put(player.getName(), number+1);
    17. //In here you can add some nice efects like FireworkEffects with my FireworkEffectPlayer v2.0 and add some messages
    18. }


    4) Then of course comes the most important part which is to Listen to the player opening a Chest or a Furnace and if it is his let him open if but if its not dont let him open it and tell him who the owner is so, for this we will need a Nice piece of code provided by CaptainBern to get a Key at a Value:

    Code:java
    1. public static <K, V> K getKeyAtValue(Map<K, V> map, V value) {
    2. if(map instanceof BiMap) {
    3. return ((BiMap<K, V>) map).inverse().get(value);
    4. }
    5. for(Map.Entry<K, V> entry : map.entrySet()) {
    6. if(entry.getValue().equals(value)) {
    7. return entry.getKey();
    8. }
    9. }
    10. return null;
    11. }


    And then we will use the PlayerInteractEvent to listen to the player opening the Chest or Furnace or block you want to block, for that we will use the following code:

    Code:java
    1. @EventHandler
    2. public void onInteract(PlayerInteractEvent event) {
    3. Player player = event.getPlayer();
    4. Block block = event.getClickedBlock();
    5.  
    6. if(getKeyAtValue(locked, block.getLocation()) != null) {
    7. String ownerName = getKeyAtValue(locked, block.getLocation());
    8.  
    9. if(!player.getName().equals(ownerName)) {
    10. event.setUseInteractedBlock(Event.Result.DENY);
    11. event.setCancelled(true);
    12. //Again here we can send the player some nice messages
    13. }
    14. }
    15. }


    5) Then we simply have to register our listeners with something like the following:

    Code:java
    1. public LockManager() {
    2. TheWalls.getInstance().getServer().getPluginManager().registerEvents(this, TheWalls.getInstance());
    3. }


    Of course that were it says TheWalls.getInstance(); you would replace it with your plugin or you can simply register the Listeners onEnable()

    6) Now we would be finished and our whole class would finish looking something like the following, remember whilst reading it that i used FireworkEffectPlayer v2.0 and i used ChatUtils because this code was for a game:

    Code:java
    1. import com.devro.thewalls.TheWalls;
    2. import com.devro.thewalls.utils.ChatUtils;
    3. import com.devro.thewalls.utils.FireworkEffectPlayer;
    4. import com.google.common.collect.BiMap;
    5. import org.bukkit.*;
    6. import org.bukkit.block.Block;
    7. import org.bukkit.entity.Player;
    8. import org.bukkit.event.Event;
    9. import org.bukkit.event.EventHandler;
    10. import org.bukkit.event.Listener;
    11. import org.bukkit.event.block.BlockPlaceEvent;
    12. import org.bukkit.event.player.PlayerInteractEvent;
    13.  
    14. import java.util.HashMap;
    15. import java.util.Map;
    16.  
    17. /**
    18. * Programmed by: DevRo_ (Erik Rosemberg)
    19. * Creation Date: 08, 01, 2014
    20. * Programmed for the TheWalls project.
    21. */
    22. public class LockManager implements Listener {
    23. private FireworkEffectPlayer fireworkEffectPlayer;
    24. private HashMap<String, Integer> players = new HashMap<String, Integer>();
    25. private HashMap<String, Location> locked = new HashMap<String, Location>();
    26.  
    27. public LockManager() {
    28. TheWalls.getInstance().getServer().getPluginManager().registerEvents(this, TheWalls.getInstance());
    29. fireworkEffectPlayer = new FireworkEffectPlayer();
    30. }
    31.  
    32. @EventHandler
    33. public void onBlockPlace(BlockPlaceEvent event) {
    34. Block block = event.getBlock();
    35. Player player = event.getPlayer();
    36. Integer number = players.get(player.getName());
    37. if (block.getType() != Material.CHEST || block.getType() != Material.FURNACE) {
    38. return;
    39. }
    40.  
    41. if (players.containsKey(player.getName()) && players.get(event.getPlayer()) == 2) {
    42. ChatUtils.sendMessage(player, ChatColor.GOLD.toString() + ChatColor.BOLD + "You have " + ChatColor.RED.toString() + ChatColor.BOLD + "0" + ChatColor.GOLD.toString() + ChatColor.BOLD + " Locks Left");
    43. return;
    44. }
    45.  
    46. locked.put(player.getName(), block.getLocation());
    47. players.put(player.getName(), number+1);
    48. fireworkEffectPlayer.playFirework(block.getLocation(), Color.YELLOW);
    49. ChatUtils.sendMessage(player, ChatColor.GOLD.toString() + ChatColor.BOLD + "You have " + ChatColor.RED.toString() + ChatColor.BOLD + players.get(player.getName()) + ChatColor.GOLD.toString() + ChatColor.BOLD + " Locks Left");
    50. }
    51.  
    52. @EventHandler
    53. public void onInteract(PlayerInteractEvent event) {
    54. Player player = event.getPlayer();
    55. Block block = event.getClickedBlock();
    56.  
    57. if(getKeyAtValue(locked, block.getLocation()) != null) {
    58. String ownerName = getKeyAtValue(locked, block.getLocation());
    59.  
    60. if(!player.getName().equals(ownerName)) {
    61. event.setUseInteractedBlock(Event.Result.DENY);
    62. event.setCancelled(true);
    63. ChatUtils.sendMessage(player, ChatColor.GOLD.toString() + ChatColor.BOLD + "You are not able to open that chest because it belongs to " + ChatColor.RED.toString() + ChatColor.BOLD + ownerName);
    64. }
    65. }
    66. }
    67.  
    68. public static <K, V> K getKeyAtValue(Map<K, V> map, V value) {
    69. if(map instanceof BiMap) {
    70. return ((BiMap<K, V>) map).inverse().get(value);
    71. }
    72. for(Map.Entry<K, V> entry : map.entrySet()) {
    73. if(entry.getValue().equals(value)) {
    74. return entry.getKey();
    75. }
    76. }
    77. return null;
    78. }
    79.  
    80. }


    Thanks for taking the Time for reading this tutorial and I hope to see this on some games.
    Regards from me And CaptainBern
     
  2. Offline

    xTrollxDudex

    DevRosemberg
    You shouldn't be storing a Location object since it is kept on mempry and prevents the chunk from being unnloaded. The serialized location will only be accessed when a player interacts with te location, therefore, the chunk should always be loaded even if not kept in memory when accessed.
     
  3. Offline

    Garris0n

    What? Since when do location objects keep chunks loaded?
     
  4. Offline

    DevRosemberg

  5. Offline

    macguy8

    DevRosemberg You're storing your data in a format of String->Location. This means that you'd be storing the players name and the latest block they placed, not all. You should be storing it in a Location->String, which stores the location and who owns it. Also, you should add support for giving back and removing the lock when broken, and preventing it from exploding. As well, players will be able to use hoppers to modify the contents of chests and furnaces, both which should be fixed. If you've got any questions about how to implement this, feel free to ask me about it on Skype (I have your contact) and then post the modified code back here. :)
     
  6. Offline

    DevRosemberg

    macguy8 Well i dont get much why to Switch from String->Location to Location->String. The hopper thing i get it and ill add it as soon as i can and how contact you in skype if you are not online mac :p
     
  7. Offline

    xTrollxDudex

    Garris0n
    Excuse me if I am wrong, but this is like storing Player objects, in terms how the object behaves when an action without the object in memory is executed, but is halted by the instance of the object.
     
  8. Offline

    Garris0n

    Location only stores a reference to a world, x, y, z, pitch, and yaw. It could potentially keep a world loaded, I suppose, but not specific chunks.
     
  9. Offline

    metalhedd


    if you do String->Location each player may only have 1 locked chest. as soon as they place another they lose their last one. if you do Location->String a player can have as many locked chests as they are able to create.
     
    xTigerRebornx likes this.
  10. Offline

    Phasesaber

    That can't be true because Locations can contain unloaded worlds.

    And DevRosemberg, could you not just do HashMap<UUID, Location[]>? That seems like it would be much easier. Just test for if the chest's location is contained within the array.

    Players have WAY more data than a simple Location.
     
  11. Offline

    dsouzamatt

    DevRosemberg I'd recommend storing players' UUIDs rather than String names in your HashMaps.

    EDIT: The above post hadn't yet shown up when I typed that /\
     
  12. Offline

    DevRosemberg

  13. DevRosemberg
    Now that we're here; you're importing org.bukkit.* (unnecessary) but still using e.g. org.bukkit.block.Block.
     
  14. Offline

    Staartvin

    You can also, instead of the two hashmaps, use metadata of blocks. Instead of storing a location, you just check the metadata of the block in the listener.
     
  15. Offline

    Script1996

    Doesn't work for me. No errors. No Message.No nothing.

    Code:
    Code:
    package ch.script.meinetruhe;
     
    import com.google.common.collect.BiMap;
    import org.bukkit.*;
    import org.bukkit.block.Block;
    import org.bukkit.entity.Player;
    import org.bukkit.event.Event;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.Listener;
    import org.bukkit.event.block.BlockPlaceEvent;
    import org.bukkit.event.player.PlayerInteractEvent; 
    import java.util.HashMap;
    import java.util.Map;
    import org.bukkit.plugin.java.JavaPlugin;
     
    public class Java extends JavaPlugin implements Listener {
    @Override
    public void onEnable() {
    getServer().getPluginManager().registerEvents(this, this);
    System.out.println("[MeineTruhe] Plugin wurde aktiviert");
    }
    @Override
    public void onDisable() {
    System.out.println("[MeineTruhe] Plugin wurde deaktiviert");
    }
    private HashMap<String, Integer> players = new HashMap<String, Integer>();
    private HashMap<String, Location> locked = new HashMap<String, Location>();
    @EventHandler
    public void onBlockPlace(BlockPlaceEvent event) {
    Block block = event.getBlock();
    Player player = event.getPlayer();
    Integer number = players.get(player.getName());
    if (block.getType() != Material.CHEST || block.getType() != Material.FURNACE) {
    return;
    }
    if (players.containsKey(player.getName()) && players.get(event.getPlayer()) == 2) {
    player.sendMessage(ChatColor.GOLD.toString() + ChatColor.BOLD + "You have " + ChatColor.RED.toString() + ChatColor.BOLD + "0" + ChatColor.GOLD.toString() + ChatColor.BOLD + " Locks Left");
    return;
    }
    locked.put(player.getName(), block.getLocation());
    players.put(player.getName(), number+1);
    player.sendMessage(ChatColor.GOLD.toString() + ChatColor.BOLD + "You have " + ChatColor.RED.toString() + ChatColor.BOLD + players.get(player.getName()) + ChatColor.GOLD.toString() + ChatColor.BOLD + " Locks Left");
    }
    @EventHandler
    public void onInteract(PlayerInteractEvent event) {
    Player player = event.getPlayer();
    Block block = event.getClickedBlock();
    if(getKeyAtValue(locked, block.getLocation()) != null) {
    String ownerName = getKeyAtValue(locked, block.getLocation());
    if(!player.getName().equals(ownerName)) {
    event.setUseInteractedBlock(Event.Result.DENY);
    event.setCancelled(true);
    player.sendMessage(ChatColor.GOLD.toString() + ChatColor.BOLD + "You are not able to open that chest because it belongs to " + ChatColor.RED.toString() + ChatColor.BOLD + ownerName);
    }
    }
    }
    public static <K, V> K getKeyAtValue(Map<K, V> map, V value) {
    if(map instanceof BiMap) {
    return ((BiMap<K, V>) map).inverse().get(value);
    }
    for(Map.Entry<K, V> entry : map.entrySet()) {
    if(entry.getValue().equals(value)) {
    return entry.getKey();
    }
    }
    return null;
    }
    }
     
  16. Offline

    DevRosemberg

    Script1996 It's broken and i forgot to fix it.
     
  17. Offline

    Script1996

    oh thats bad :(

    Will you do a new Tutorial ? :)
     
Thread Status:
Not open for further replies.

Share This Page