Discussion in 'Resources' started by _Belknap_, May 30, 2014.

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


    Hi, I noticed that on PlayerInteractEvent, when you right click any sword the event only fires once. As it turns out, the solution is very simple to make it so that the event repeats itself like it would with any other item. In a sense, you could call it PlayerBlockEvent. Already, PlayerInteractEvent fires when you right click a sword, but only once. What this does is once the player right clicks the sword, a delayed task is run that checks if the player is still right clicking or, "blocking" with the sword. Then, if they are, it just repeats the event over again. This isn't laggy at all, and as some of you know is used on some servers such as Mineplex, which uses it in almost all of their minigames. Here are the steps:
    Step 1:
    Place this below your class opening.(Ex: public class ExampleClass extends Blah implements Blah {
    1. private int taskID = -1;

    Step 2: Insert this code:
    1. @EventHandler
    3. public void onBlock(final PlayerInteractEvent e) {
    5. //Checks if player is right clicking a sword
    7. if (e.getAction() == Action.RIGHT_CLICK_AIR) {
    9. if (e.getItem().getType() == Material.STONE_SWORD) {
    11. //Runs a repeating self-cancelling task. You can change the interval at which this task repeats itself
    13. taskID = this.getServer().getScheduler().scheduleSyncRepeatingTask(this, new Runnable() {
    14. public void run() {
    15. //Checks if the player is blocking, and then calls the event over again
    16. if (e.getPlayer().isBlocking()) {
    17. //Put Code Here vvvvvvvvv ( Mine is an example)
    18. e.getPlayer().launchProjectile(Snowball.class);
    19. //Put Code Here ^^^^^^^
    20. }else{
    21. //If they aren't blocking, cancels the task.
    22. Bukkit.getServer().getScheduler().cancelTask(taskID);
    23. }
    24. }},0L,4L);
    25. }
    26. }
    27. }

    Please leave a like!
    minelazz and Phasesaber like this.
  2. Offline


    Pretty neat! Not sure what applications this has though, maybe driving a car....
    Dang it, now I'm going to be thinking of making a mario kart minigame!
  3. Offline


    I wonder where you got this code.
  4. Offline


    What do you mean?
  5. Offline


    This doesn't look like Mineplex's or anything.
  6. Offline


    Mineplex source code was leaked, and read his last sentence, "and as some of you know is used on some servers such as Mineplex"
  7. Offline


    That doesn't necessarily mean it's from their source.

    That said, this is an incredibly stupid way to do any sort of blocking action. Recursively calling an event with a scheduler? You're going to screw up other plugins and cause unnecessary lag.
  8. Offline


    I don't get any lag from it, and even with 15 other plugins. Explain how this could be laggy

    No I actually didn't get it from them. Some of the things they do are way beyond my reach.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
    Last edited by a moderator: Jul 1, 2016
  9. Offline


    It's not necessarily laggy, it's just a waste of CPU.

    Also, my main point was that it's a terrible way to go about it and calls the PlayerInteractEvent, which in turn will trigger plugins using that event, screwing them up. And it recursively calls it, at that.

    What you should've done was schedule a self-cancelling repeating BukkitRunnable.
    _Belknap_, LegitJava and Phasesaber like this.
  10. Offline


    Example? (I'm terrible with self-cancelling ones)

    He meant the idea of the blocking was used on the Mineplex Server, if src code was leaked, we'd all have the best server there is. :p

    It's all just Listeners and Runnables. And the occasional Arena & ArenaManager class.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
    Last edited by a moderator: Jul 1, 2016
  11. Offline


  12. Offline


  13. Offline


    Thanks for the feedback! I'll change it soon.
    EDIT: Changed it!
  14. Offline


  15. Offline


    I get how yours is cleaner and more organized, but I think that mine still works good enough anyways. Also, is there really a huge difference? I get that yours is better, but it doesn't mean that my way works badly. I agree with you on the fact that my first post was incredibly stupid, but I don't really think that my way is that much different or worse than yours. Of course, if it is still an incredibly stupid idea, then comment, because I love the feedback, as it helps me out hugely. That said, don't call it stupid because of a minor fix that you think should be made. Obviously, it could be cleaner, but I just wanted to post my ideas, as I found this problem to be very annoying myself, and thought that I could help people out with it.
    EDIT: Also, I see how yours is better, as it is cleaner, simpler, and has the ability to change variables within it, such as if you were to do a cooldown. With the scheduleRepeatingTask or scheduleDelayedTask, you can only place final variables inside the run() method, which completely removes the option for a cooldown, because they are unchangeable.
  16. Offline


    _Belknap_ Well, for one, it's just best not to do the whole task ID thing. It's not very clean and starts to get really messy when you have multiple schedulers, etc. It doesn't really matter, however, since you're providing code to others (and thus teaching them habits in the process), you should always write the best possible code.

    Also, I didn't call the current one stupid. I don't know where you're getting that from. The original one was terrible and caused tons of problems, the current one could just use a bit of cleanup.

    Edit: Also, the Runnable can have instance variables just like the BukkitRunnable and any other anonymous class. You can just cancel a BukkitRunnable internally, which is cleaner. You could do the same thing with a normal runnable and scheduler methods, I just don't like how it looks.
  17. Offline


    Sorry, you just seemed really strict about how you thought I should do it, and I didn't want you to dismiss my methods as trash because of a small mistake. Anyways, thanks for the help! I really appreciated that your feedback. By the way, off of this, I made a quick little class that runs a timer, and tried doing it the way you suggested. If you wouldn't mind giving feedback on it, I realize that I need some help in this area of coding:
    1. package;
    3. import java.util.ArrayList;
    4. import java.util.HashMap;
    5. import java.util.List;
    6. import java.util.Map;
    8. import org.bukkit.entity.Player;
    9. import org.bukkit.plugin.Plugin;
    10. import org.bukkit.scheduler.BukkitRunnable;
    12. public class Timer {
    13. //The seconds left. If the seconds set is less than 0,
    14. //it just cancels the timer, as shown below
    15. private int seconds = -1;
    16. //The starting time
    17. private int startingTime = -1;
    18. //The plugin this task runs off of
    19. private Plugin plugin;
    20. //My way to cancel the timer
    21. private boolean cancelled = false;
    22. //The times that their associated messages are sent
    23. private Map<Integer,String> mTimes = new HashMap<Integer,String>();
    24. //The players the messages will be sent to
    25. private Player[] players = null;
    27. //The constructor
    28. public Timer(Plugin plugin, int seconds,Player...players) {
    29. this.plugin = plugin;
    30. this.seconds = seconds;
    31. this.startingTime = seconds;
    32. this.players = players;
    33. this.start();
    34. //Defines all the variables and starts the timer.
    35. }
    37. public void start() {
    39. new BukkitRunnable() {
    40. public void run() {
    41. //Due to the fact that you can't directly change the "seconds
    42. //left" out of the BukkitRunnable(), I keep track of the time
    43. //inside the BukkitRunnable(), and then change the actual seconds
    44. //left with a method, like accessing data from seperate classes.
    45. int time = getTimeLeft();
    46. //^^^^^^^^
    47. //Checks if the timer hasn't been stopped, and that it isn't less than 0
    48. if (!isCancelled() && !(getTimeLeft() < 0)) {
    49. //Runs through each time in the mTimes Map, and checks if the current
    50. //time is equal to one of its times. If so, it sends a message to
    51. //each required player that matches up with that time.
    52. for (Integer time1: mTimes.keySet()) {
    53. if (seconds == time1) {
    54. for (Player p : players) {
    55. //This just makes the person using this class' job easier.
    56. //If they include the time left in their message, it returns
    57. //the starting time, because they added the messages before its starts
    58. //Basically, it replaces that starting time with the current time
    59. p.sendMessage(mTimes.get(time1).replaceAll(Integer.toString(startingTime),Integer.toString(seconds) ));
    60. }
    61. }
    62. }
    63. //Counts down the timer, and assigns the actual seconds to the value of the time
    64. //integer
    65. time--;
    66. setTimeLeft(time);
    67. //If the time left is less than 0 or the timer is cancelled, stops the timer.
    68. }else{
    69. this.cancel();
    70. return;
    71. }
    73. }
    75. }.runTaskTimer(plugin, 0L, 20L);
    76. }
    78. public int getTimeLeft() {
    79. //The outside method to set the time inside the BukkitRunnable()
    80. return seconds;
    81. }
    83. public boolean isCancelled() {
    84. //Returns if the timer is stopped
    85. return cancelled;
    86. }
    88. public void stop() {
    89. //Basically the setter method for the cancelled boolean. It stops the timer.
    90. this.cancelled = true;
    91. }
    92. //Returns all the times that messages are sent at
    93. public List<Integer> getMessageTimes() {
    94. List<Integer> times = new ArrayList<Integer>();
    95. for (Integer time : mTimes.keySet()) {
    96. times.add(time);
    98. }
    99. return times;
    100. }
    101. //Returns all the messages that are sent
    102. public List<String> getMessages() {
    103. List<String> messages = new ArrayList<String>();
    104. for (String message : mTimes.values()) {
    105. messages.add(message);
    106. }
    107. return messages;
    108. }
    109. //Adds a message to the mTimes HashMap
    110. public void addMessage(String message, int time) {
    111. mTimes.put(time, message);
    112. }
    113. //Removes a message, either by the message itself or the time that it is sent at
    114. public void removeMessage(Object key) {
    115. if (key instanceof String) {
    116. for (Integer time : mTimes.keySet()) {
    117. if (mTimes.get(time).equals(key)) {
    118. mTimes.remove(key);
    119. }
    120. }
    121. }else if (key instanceof Integer) {
    122. mTimes.remove(key);
    124. }
    125. }
    126. //Sets the time left
    127. public void setTimeLeft(int time) {
    128. this.seconds = time;
    129. }
    131. //Returns the starting time of the timer.
    132. public int getStartingTime() {
    133. return startingTime;
    134. }
    135. }

    And the way you could use it:
    1. @EventHandler
    2. public void onJoin(PlayerJoinEvent e) {
    3. Timer timer = new Timer(this, 30,e.getPlayer());
    4. timer.addMessage(ChatColor.GREEN + "There is " + timer.getTimeLeft() + " seconds left!", 20);
    5. timer.addMessage(ChatColor.GREEN + "There is " + timer.getTimeLeft() + " seconds left!", 10);
    6. timer.addMessage(ChatColor.GREEN + "There is " + timer.getTimeLeft() + " seconds left!", 5);
    7. timer.addMessage(ChatColor.GREEN + "There is " + timer.getTimeLeft() + " seconds left!", 4);
    8. timer.addMessage(ChatColor.GREEN + "There is " + timer.getTimeLeft() + " seconds left!", 3);
    9. timer.addMessage(ChatColor.GREEN + "There is " + timer.getTimeLeft() + " seconds left!", 2);
    10. timer.addMessage(ChatColor.GREEN + "There is " + timer.getTimeLeft() + " seconds left!", 1);
    11. timer.addMessage(ChatColor.GREEN + "Game starting...", 0);
    13. }
  18. Offline


    Cool :p

    A few things, because why not I guess.
    -Perhaps instead of creating a new anonymous BukkitRunnable, you could make the class itself extend BukkitRunnable. That would probably be a bit cleaner. You can then also call cancel() from the stop method instead of using a variable (you could technically do this anyway by saving the BukkitRunnable instance, but, again, extending would be cleaner).
    -You'll need a variable in the string, like "%time%", and then you can just use String#replace(String, String) when it's time to send the message. The way it is now, all the messages will state the time when the class is instantiated :p
    -Perhaps make addMessage() return the timer? Then you can just chain it.
    -Perhaps "start" should be a method you call when you're done adding messages instead.
    -Saving players is generally a bad idea. In this case, the class is temporary and will be garbage collected, so it doesn't really matter, but if it were some sort of permanent class, you should save the UUID or use some sort of weak map/list implementation.
    -You should try uploading to something like because Bukkit screws up syntax if you edit.
    _Belknap_ likes this.
  19. Offline


    Great, I'll change it for some of those! I will probably just to a String[] on the constructor instead of doing addMessage() for every message anways, and while I will keep addMessage(), that'll just make it easier. Also, I did realize too that I probably should've done the start() after. My final comment is that I prefer when adding a few pieces of extra data to an object such as a Player, I don't like extending that object, as it is annoying to have all the extra methods. Instead, I prefer creating an instance of the object that I want to add pieces of data for, and then just add my own methods. I still keep the principle methods though. Its just a more efficient solution so that I don't mess with any of bukkit's data by creating a new Player or Entity. I do extend things like Events though. Anways, here is what I prefer:
    1. private Player p = null;
    3. public Player getPlayer() {
    4. return p;
    6. public void setPlayer(Player p) {
    7. this.p = p;

    That way, I can just access the player and do all the methods by simply getting the player instead of creating an entire new type of Player

    I use that over:

    1. public class NewPlayer extends Player
    2. //Or
    3. public class NewEntity extends Entity

    Thanks so much for your help!
  20. Offline


    There's no reason to ever extend Player/Entity/etc, I'm not sure what you mean there.
  21. Offline


    Also note that both Player and Entity are interfaces which need to be implemented, not extended. Further note that you will need to nullify the Player object in your wrapper unless you remove the entire wrapper itself, which the GC will handle smoothly.
  22. Offline


    No, you just wanted me to extend BukkitRunnable. I just wanted to show you why I didn't :D

    Got it!

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
    Last edited by a moderator: Jul 1, 2016
  23. Offline


    No no, those are two different things. Extending the Player/Entity or whatever doesn't make any sense because they're interfaces and the extensions wouldn't actually do anything. You would have to extend the craft/nms classes and then inject the new versions into the server.

    Extending the BukkitRunnable, on the other hand, actually does make sense. You're making an anonymous one inside anyway, so I don't see why you wouldn't just extend the actual class.
Thread Status:
Not open for further replies.

Share This Page