Solved Play nbt file song

Discussion in 'Plugin Development' started by DevMax_Plg, Jun 17, 2019.

  1. Offline

    DevMax_Plg

    Hey guys,

    I need your help with a plugin. I'm trying to make a plugin with which you can play nbt files that contain songs directly to a player. I found nothing on Google abput it and therefore I ask if anyone of you can help me.

    I would be happy if anyone can give me an approach.

    Kind regards.

    Max
     
  2. Offline

    KarimAKL

    @DevMax_Plg I think you can create a resource pack and force players to use it, then play a song using the Player#playSound(String) method.
     
  3. Offline

    DevMax_Plg

    @KarimAKL Yes that is a good idea but i found a plugin that can play noteblok songs nbt files and i want to do it like that and not to force the player to download a resource pack.

    Here is the plugin --> https://dev.bukkit.org/projects/servermusic

    And i also would like to do this without the noteblock api. I mean that i create my own NoteblockAPI and also an Player for nbt files that play musik.
     
  4. Offline

    KarimAKL

  5. Offline

    DevMax_Plg

    I need also help with another problem.

    I tried to build an Bedwars Plugin that protects the normal map so that you can build and break you own blocks but after a game the plugin should reset or reload the map or an area that I marked. How can I do this?
     
  6. Offline

    KarimAKL

    @DevMax_Plg Did you get the songs working?

    Save the map before the game starts, then when the game is finished you set the map back.
     
  7. Offline

    DevMax_Plg

    But how do i do that. I need a Keyword. How do i save a map and than reset the map. also i dont know but i think it is better if i save an marked area and reset it after the game. also i must protekt the map so that you can build and break just your own blocks and not any of the blocks from the map.
     
  8. Offline

    KarimAKL

    @DevMax_Plg You could save the map like like this:
    Code:Java
    1. /*loop all blocks in area you want to save*/ {
    2. map.put(location, block);
    3. }

    Then set it back like this:
    Code:Java
    1. for (Entry<Location, Block> entry : map.entrySet()) {
    2. entry.getKey().getBlock().setType(entry.getValue().getType());
    3. // And if you use a version lower than 1.13
    4. entry.getKey().getBlock().setData(entry.getValue().getData());
    5. }

    That should save all blocks in the area to a location in a map.
    To stop players from breaking the map's blocks you could do something like this:
    Code:Java
    1. /*BlockBreakEvent*/ {
    2. if (!map.containsKey(event.getBlock().getLocation())) return;
    3. if (map.get(event.getBlock().getLocation()).getType() == Material.AIR) {
    4. event.getPlayer().sendMessage("You cannot break the map");
    5. e.setCancelled(true);
    6. }
    7. }

    If there's anything you don't understand about this then let me know.
     
  9. Offline

    bwfcwalshy Retired Staff

    @KarimAKL For the breaking, I'd likely just use a set with location. No need to cache the entire Block object.

    Also, small speed improvement, don't run a contains and a get. You can just do a get and check if it isn't null (which is what contains does). It isn't really noticeable until on a large scale but when running a lot these improvements are good!
     
    Last edited: Jun 19, 2019
    DevMax_Plg and KarimAKL like this.
  10. Offline

    DevMax_Plg

    Yes i dont understand anything :D
    Just kidding
    i know that map is a HashMap
    but i dont understand the rest of the code
     
    Last edited: Jun 20, 2019
  11. Offline

    KarimAKL

    @DevMax_Plg
    For the first section we loop all the blocks in the area, we then save the block at the location in the map.

    Then when we want to set it back, we loop over all the entries in the map, that should get us all the locations and the blocks we want to set at the location. We then get the block at the location saved and set it to the block we saved.

    We then listen to the BlockBreakEvent and checks if the map contains the block that the player is trying to break, if it does then we check if the original block at that location is air, if it is then we let them break it, if not we cancel.

    I hope that sums it up.
     
  12. Offline

    DevMax_Plg

    Not realy i know how this works but i have problems with using it in my code.
     
    Last edited by a moderator: Jun 20, 2019
  13. Offline

    KarimAKL

    @DevMax_Plg Could you elaborate on why you have problems using it?
     
  14. Offline

    DevMax_Plg

    Yes. I dont know how to do the loop in the first code snipet but think it's something with a "for-loop".
    For the second code i dont know what entry means. Is it another HashMap?
    I understand the third code but i can't use it because i don't understand the other two.
     
  15. Offline

    KarimAKL

    @DevMax_Plg For the first one; you might be able to use this thread for help:
    https://bukkit.org/threads/looping-through-blocks-in-a-radius.237409/
    For the second one; one Entry<K,V> is a key/value pair of the map, if you look at the 'Map<K,V>#entrySet()' method, you'll see it returns a Set<Entry<K,V>>, you loop through that Set to get the pairs.
    Let me know if there's still something you don't understand.
     
    DevMax_Plg likes this.
  16. Offline

    DevMax_Plg

    So first of all Thanks a lot for your help.
    I really appreciate that.
    I don't understand this post : https://bukkit.org/threads/looping-through-blocks-in-a-radius.237409/
    I'm still a beginner with these plugin things.
    Maybe you could show me a better example if it's ok for you?
     
  17. Offline

    KarimAKL

    @DevMax_Plg Imagine this being the view from above some blocks:
    Code:
       Z
    X  0    1    2
    0 [  ] [  ] [  ]
    1 [  ] [  ] [  ]
    2 [  ] [  ] [  ]
    
    We then loop through those block like this:
    Code:Java
    1.  
    2. for (int x = 0; x < 3; x++) {
    3. for (int z = 0; z < 3; z++) {
    4. // Loop through Y and and set it to the location as well
    5. // I can't show it like this though. :/
    6. Location loc = new Location(x, 0, z);
    7. map.put(loc, loc.getBlock());
    8. }
    9. }
     
  18. Offline

    DevMax_Plg

    Ok i understand
    But when you make a new location it would save the area at 0 on the z and 0 on the x?
    And how do I load the whole thing like in the famouse worldedit that has the copy and paste function?
     
    Last edited: Jun 21, 2019
  19. Offline

    KarimAKL

  20. Offline

    DevMax_Plg

    So at the moment i have this...
    Code:Java
    1. private static HashMap<Location, Block> SaveMap = new HashMap<>();
    2.  
    3. public static void onCommand(CommandSender sender, Command command, String label, String[] args) {
    4. if (sender instanceof Player) {
    5. Player player = (Player) sender;
    6. if(args[1].equalsIgnoreCase("save")) {
    7. if(args.length == 6) {
    8. for (int x = Integer.parseInt(args[2]); x < Integer.parseInt(args[4]); x++) {
    9. for (int y = Integer.parseInt(args[3]); y < Integer.parseInt(args[5]); y++) {
    10. Location loc = new Location(player.getWorld() ,x, y, 0);
    11. SaveMap.put(loc, loc.getBlock());
    12. }
    13. }
    14. }
    15. } else if (args[1].equalsIgnoreCase("load")) {
    16. player.sendMessage(SaveMap.toString());
    17. }
    18. }
    19. }


    But when i execute the /save and then /load command the server sends me this "{}" and i think thats an empty hashmap

    i hope you can help me

    I found the answer by myself i use the args direct and my coordinates are 100 100 98 98

    that means my code does this

    x=100
    x < 98

    so i know how to fix this

    it's just the lower and higher number.

    My code looks like this

    Code:Java
    1. if(args[1].equalsIgnoreCase("save")) {
    2. if(args.length == 8) {
    3. for (int x = Integer.parseInt(args[2]); x < Integer.parseInt(args[5]); x++) {
    4. for (int z = Integer.parseInt(args[4]); z < Integer.parseInt(args[7]); z++) {
    5. for (int y = Integer.parseInt(args[3]); y < Integer.parseInt(args[6]); y++) {
    6. Location loc = new Location(player.getWorld(), x, y, z);
    7. SaveMap.put(loc, loc.getBlock().getType().toString());
    8. }
    9. }
    10. }
    11. }
    12. } else if (args[1].equalsIgnoreCase("load")) {
    13. player.sendMessage(SaveMap.toString());
    14. }


    But when i save and load it gives me this output:

    Code:Java
    1. Location{world=CraftWorld{name=world},x=99.0,y=98.0,z=49.0,pitch=0.0,yaw=0.0}=STONE
    2. Location{world=CraftWorld{name=world},x=99.0,y=99.0,z=49.0,pitch=0.0,yaw=0.0}=STONE
    3. Location{world=CraftWorld{name=world},x=98.0,y=98.0,z=49.0,pitch=0.0,yaw=0.0}=STONE
    4. Location{world=CraftWorld{name=world},x=98.0,y=99.0,z=49.0,pitch=0.0,yaw=0.0}=STONE


    That means it skips the z value

    How can i fix that?

    i've fixed it kind of

    Code:Java
    1. if(args[1].equalsIgnoreCase("save")) {
    2. if(args.length == 8) {
    3. for (int x = Integer.parseInt(args[2]); x <= Integer.parseInt(args[5]); x++) {
    4. for (int y = Integer.parseInt(args[3]); y <= Integer.parseInt(args[6]); y++) {
    5. for (int z = Integer.parseInt(args[4]); z <= Integer.parseInt(args[7]); z++) {
    6. Location loc = new Location(player.getWorld(), x, y, z);
    7. SaveMap.put(loc, loc.getBlock().getType().toString());
    8. }
    9. }
    10. }
    11. }
    12. } else if (args[1].equalsIgnoreCase("load")) {
    13. player.sendMessage(SaveMap.values().toString());
    14. }


    I have a 3 x 3 x 3 Block out of Stone so it should return the word "STONE" 27 Times

    But i only get the word "STONE" 18 Times as message

    what am i doing wrong

    please help

    And again fixed it myself

    the coordinates i input where false

    Now i am on this part of your code

    My code is following:

    Code:Java
    1. if(args[1].equalsIgnoreCase("save")) {
    2. if(args.length == 8) {
    3. for (int x = Integer.parseInt(args[2]); x <= Integer.parseInt(args[5]); x++) {
    4. for (int y = Integer.parseInt(args[3]); y <= Integer.parseInt(args[6]); y++) {
    5. for (int z = Integer.parseInt(args[4]); z <= Integer.parseInt(args[7]); z++) {
    6. Location loc = new Location(player.getWorld(), x, y, z);
    7. SaveMap.put(loc, loc.getBlock());
    8. }
    9. }
    10. }
    11. }
    12. } else if (args[1].equalsIgnoreCase("load")) {
    13. for (Entry<Location, Block> entry : SaveMap.entrySet()) {
    14. entry.getKey().getBlock().setType(entry.getValue().getType());
    15. }
    16. }


    when i use "load" it does nothing

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 30, 2019
  21. Offline

    KarimAKL

    @DevMax_Plg Check the length of the arguments before using 'if (args[1].equalsIgnoreCase("save"))'.
    Try printing the contents of the map.
     
  22. Offline

    DevMax_Plg

    Thats ok because my command is: /lbs savemap save x y z x y z


    When i try printig entry out it outputs all the blocks and positions so when i use your code it should work but it doesnt
    here is the hole code

    Code:Java
    1. package de.max.lobby.commands;
    2.  
    3. import java.util.HashMap;
    4. import java.util.Map.Entry;
    5.  
    6. import org.bukkit.Location;
    7. import org.bukkit.block.Block;
    8. import org.bukkit.command.Command;
    9. import org.bukkit.command.CommandSender;
    10. import org.bukkit.entity.Player;
    11.  
    12. public class SaveMap {
    13.  
    14. private static HashMap<Location, Block> SaveMap = new HashMap<>();
    15.  
    16. public static void onCommand(CommandSender sender, Command command, String label, String[] args) {
    17. if (sender instanceof Player) {
    18. Player player = (Player) sender;
    19. if(args[1].equalsIgnoreCase("save")) {
    20. if(args.length == 8) {
    21. for (int x = Integer.parseInt(args[2]); x <= Integer.parseInt(args[5]); x++) {
    22. for (int y = Integer.parseInt(args[3]); y <= Integer.parseInt(args[6]); y++) {
    23. for (int z = Integer.parseInt(args[4]); z <= Integer.parseInt(args[7]); z++) {
    24. Location loc = new Location(player.getWorld(), x, y, z);
    25. SaveMap.put(loc, loc.getBlock());
    26. }
    27. }
    28. }
    29. }
    30. } else if (args[1].equalsIgnoreCase("load")) {
    31. for (Entry<Location, Block> entry : SaveMap.entrySet()) {
    32. entry.getKey().getBlock().setType(entry.getValue().getType());
    33. }
    34. }
    35. }
    36. }
    37.  
    38. }[Syntax][/Syntax]
     
  23. Offline

    KarimAKL

    Sure, but if you don't type any arguments, or you only type one argument, you'll get an IndexOutOfBoundsException.
    Okay, so the map contains the elements? In that case, try printing a message inside the loop (the one in 'load'), and then check if it gets printed, if so, setting the block's type isn't working for some reason.
    EDIT: I'm not 100% sure but try saving 1 block, load the 1 block and print the material before saving and after loading. (Hope that made sense)
    I think the block instance inside the map might have the material updated, not sure though. :7
     
  24. Offline

    DevMax_Plg

    I don't know what you mean.
    Maybe you can help me better when we write over discord if it's ok for you

    I already tried that and it does output a message several times

    didnt get it

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 30, 2019
  25. Offline

    KarimAKL

    An index out of bounds happens when you try to get something from a list/array that doesn't exist. e.g. The list has 3 values and you try to get the fourth value. That'll throw an IndexOutOfBoundsException.
    Good, that's what we want. :)
    Didn't get it? Do you mean that you didn't understand what i meant? In that case, maybe this'll explain it better?
    Code:Java
    1. // Saving
    2. map.put(location, location.getBlock());
    3. System.out.println(map.get(location).getType().name());
    4.  
    5. // Loading
    6. System.out.println(map.get(location).getType().name());
    7. map.remove(location);

    Then check if the material is the same as the one when you saved it.
     
  26. Offline

    DevMax_Plg

    Ok when i try this and when i save the whole thing it says for example stone

    when i try to load that it says stone

    when i replace the stone with wood and try to load it another time it says wood

    another time that's my newest script:

    Code:Java
    1. package de.max.lobby.commands;
    2.  
    3. import java.util.HashMap;
    4. import java.util.Map.Entry;
    5.  
    6. import org.bukkit.Location;
    7. import org.bukkit.block.Block;
    8. import org.bukkit.command.Command;
    9. import org.bukkit.command.CommandSender;
    10. import org.bukkit.entity.Player;
    11.  
    12. public class SaveMap {
    13.  
    14. private static HashMap<Location, Block> SaveMap = new HashMap<>();
    15.  
    16. public static void onCommand(CommandSender sender, Command command, String label, String[] args) {
    17. if (sender instanceof Player) {
    18. Player player = (Player) sender;
    19. if(args[1].equalsIgnoreCase("save")) {
    20. if(args.length == 8) {
    21. for (int x = Integer.parseInt(args[2]); x <= Integer.parseInt(args[5]); x++) {
    22. for (int y = Integer.parseInt(args[3]); y <= Integer.parseInt(args[6]); y++) {
    23. for (int z = Integer.parseInt(args[4]); z <= Integer.parseInt(args[7]); z++) {
    24. Location loc = new Location(player.getWorld(), x, y, z);
    25. SaveMap.put(loc, loc.getBlock());
    26. System.out.println(SaveMap.get(loc).getType().name());
    27. }
    28. }
    29. }
    30.  
    31. }
    32. } else if (args[1].equalsIgnoreCase("load")) {
    33. for (Entry<Location, Block> entry : SaveMap.entrySet()) {
    34. entry.getKey().getBlock().setType(entry.getValue().getType());
    35. System.out.println(entry.getValue().getType().name());
    36. player.sendMessage("In For-Loop...");
    37. }
    38. player.sendMessage("Loaded!");
    39. }
    40. }
    41. }
    42.  
    43. }


    it looks like the hashmap automatically updates it self
     
  27. Offline

    KarimAKL

    @DevMax_Plg Okay, try changing the type of the map to <Location, Material> and then save the block's type instead of the block. That should work.
     
  28. Offline

    DevMax_Plg

    it works
    thanks a lot
    but one last thing it dont save any wool blocks
     
    Last edited: Jul 5, 2019
  29. Offline

    KarimAKL

    @DevMax_Plg What do you mean? You are saving the material, it should save the type no matter what block it is.
     
  30. Offline

    DevMax_Plg

    my server is on version 1.9
     
    Last edited: Jul 6, 2019

Share This Page