Resource PotionEffectsManager

Discussion in 'Spigot Plugin Development' started by WAS, Apr 13, 2017.

  1. WAS

    WAS

    Thought id share this since it may come in handy for other people. Manage multiple potion effects on multiple players. Feel free to add to the Gist and improve upon the manager.

    GitHubGist:

    Code (Java):
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;

    import org.bukkit.entity.Player;
    import org.bukkit.Location;
    import org.bukkit.World;
    import org.bukkit.potion.PotionEffect;

    /*************************
    *
       Copyright (c) 2017 Jordan Thompson (WASasquatch)

       Permission is hereby granted, free of charge, to any person obtaining a copy
       of this software and associated documentation files (the "Software"), to deal
       in the Software without restriction, including without limitation the rights
       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       copies of the Software, and to permit persons to whom the Software is
       furnished to do so, subject to the following conditions:

       The above copyright notice and this permission notice shall be included in all
       copies or substantial portions of the Software.

       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
       SOFTWARE.

    *
    **************************/


    public class PotionEffectsManager {

      private Map<String, Collection<Player>> playerSets = new HashMap<String, Collection<Player>>();
      private Map<String, Collection<PotionEffect>> potionSets = new HashMap<String, Collection<PotionEffect>>();

      public boolean addAllEffects(String set, Collection<PotionEffect> effects) {
         if ( ! ( playerSets.containsKey(set) ) ) {
           createPotionSet(set);
         }
         Collection<PotionEffect> potionEffects = potionSets.get(set);
         potionEffects.addAll(effects);
      potionSets.put(set, potionEffects);
      if ( potionSets.get(set).containsAll(effects) ) {
         return true;
      }
      return false;
      }

      public boolean addEffect(String set, PotionEffect effect) {
         if ( ! ( potionSets.containsKey(set) ) ) {
           createPotionSet(set);
         }
         Collection<PotionEffect> potionEffects = potionSets.get(set);
      return potionEffects.add(effect);
      }

      public boolean addAllPlayers(String set, Collection<Player> players) {
         if ( ! ( playerSets.containsKey(set) ) ) {
           createPlayerSet(set);
         }
         Collection<Player> playerSet = playerSets.get(set);
      playerSet.addAll(players);
      playerSets.put(set, playerSet);
      if ( playerSets.get(set).containsAll(players) ) {
         return true;
      }
      return false;
      }

      public boolean addPlayer(String set, Player player) {
         if ( ! ( playerSets.containsKey(set) ) ) {
           createPlayerSet(set);
         }
      return playerSets.get(set).add(player);
      }

      public boolean addPlayersInRadius(String set, Location center, World world, int radius, boolean ellipsis) {
      Collection<Player> ep = Collections.emptySet();
      List<Player> players = world.getPlayers();
      if ( ellipsis ) {
         radius = ( radius * radius );
      }
      for ( Player player : players ) {
        if ( center.distanceSquared(player.getLocation()) <= radius ) {
        ep.add(player);
         }
      }
      if ( ep.size() > 0 ) {
      addAllPlayers(set, ep);
      return true;
      }
      return false;
      }

      public Collection<Player> applySetToPlayers(String potionSet, String playerSet) {
         Collection<Player> rogues = Collections.emptySet();
      for ( Player player: playerSets.get(playerSet) ) {
      if ( ! ( player.addPotionEffects(potionSets.get(potionSet)) ) ) {
         rogues.add(player);
      }
      }
      if ( rogues.size() > 0 ) {
         // Something has gone wrong with applying effects to these "rogues"
         return rogues;
      }
      return Collections.emptySet();
      }

      public Collection<Player> applySetToAllPlayers(String potionSet) {
         Collection<Player> rogues = Collections.emptySet();
         for ( Collection<Player> players : playerSets.values() ) {
        for ( Player player : players ) {
        if ( ! ( player.addPotionEffects(potionSets.get(potionSet)) ) ) {
           rogues.add(player);
        }
        }
         }
      if ( rogues.size() > 0 ) {
         // Something has gone wrong with applying effects to these "rogues"
         return rogues;
      }
      return Collections.emptySet();
      }

      public Collection<Player> applyAllSetsToPlayers(String set) {
         Collection<Player> rogues = Collections.emptySet();
         Collection<PotionEffect> potionEffects = new ArrayList<PotionEffect>();
         for ( Collection<PotionEffect> effects : potionSets.values() ) {
           potionEffects.addAll(effects);
         }
         for ( Player player : playerSets.get(set) ) {
           if ( ! ( player.addPotionEffects(potionEffects) ) ) {
             rogues.add(player);
           }
         }
      if ( rogues.size() > 0 ) {
         // Something has gone wrong with applying effects to these "rogues"
         return rogues;
      }
      return Collections.emptySet();
      }

      public Collection<Player> applyAllSetsToAllPlayers() {
         Collection<Player> rogues = Collections.emptySet();
         Collection<PotionEffect> potionEffects = new ArrayList<PotionEffect>();
         for ( Collection<PotionEffect> effects : potionSets.values() ) {
           potionEffects.addAll(effects);
         }
         for ( Collection<Player> players : playerSets.values() ) {
        for ( Player player : players ) {
        if ( ! ( player.addPotionEffects(potionSets.get(potionEffects)) ) ) {
           rogues.add(player);
        }
        }
         }
      if ( rogues.size() > 0 ) {
         // Something has gone wrong with applying effects to these "rogues"
         return rogues;
      }
      return null;
      }

      public boolean applyEffectsToPlayer(String set, Player player) {
      return player.addPotionEffects(potionSets.get(set));
      }

      // Create or reset a player set
      public void createPlayerSet(String set) {
         playerSets.put(set, Collections.emptySet());
      }

      // Create or reset a potion set
      public void createPotionSet(String set) {
         potionSets.put(set, Collections.emptySet());
      }

      public Collection<PotionEffect> getPotionSet(String set) {
         return potionSets.get(set);
      }

      public Collection<Player> getPlayerSet(String set) {
         return playerSets.get(set);
      }

      public boolean removeAllEffects(String set, Collection<PotionEffect> effects) {
      return potionSets.get(set).removeAll(effects);
      }

      public boolean removeEffect(String set, PotionEffect effect) {
      return potionSets.get(set).remove(effect);
      }

      public boolean removeAllPlayers(String set, Collection<Player> players) {
      return playerSets.get(set).removeAll(players);
      }

      public boolean removePlayer(String set, Player player) {
      return playerSets.get(set).remove(player);
      }

      public void reset() {
         resetPotionSets();
         resetPlayerSets();
      }

      public void resetPotionSets() {
      potionSets = new HashMap<String, Collection<PotionEffect>>();
      }

      public void resetPlayerSets() {
      playerSets = new HashMap<String, Collection<Player>>();
      }

    }
     
    #1 WAS, Apr 13, 2017
    Last edited: Apr 15, 2017
  2. WAS

    WAS

    Updated with a new version with set based management for multiple uses. Again feel free to make improvements.

    Code (Java):

      @EventHandler(priority = EventPriority.HIGHEST)
       public void tntExplosion(EntityExplodeEvent e) {
        if ( ! ( e.getEntity() instanceof TNTPrimed ) || e.isCancelled() ) return;

        // Start Potion Effects Manager (This generally would be done elsewhere)
         PotionEffectsManager pem = new PotionEffectsManager();
       
         // Add potion effects (This generally would probably be done elsewhere so you can reuse sets)

         // Create a new potion set. This is also done with addAllPlayers and addPlayer (or with effects)
         // String playerSet
         pem.createPlayerSet("explosion_event");
         Collection<PotionEffect> effects = new ArrayList<PotionEffect>();
         effects.add(new PotionEffect(PotionEffectType.SLOW, 1200, 1.0));
         effects.add(new PotionEffect(PotionEffectType.BLINDNESS, 800, 1.0));
         // String potionSet, Collection<PotionEffect> effects
         pem.addAllEffects("explosion_potion_effects", effects);

         // Do stuff...
         int radius = 15;
       
         // Apply Potion Effects to Players in explosion_event

         // String setName, Location loc, World world, int radius, boolean isEllipsis
         pem.addPlayersInRadius("explosion_event", e.getEntity().getLocation(), e.getEntity().getWorld(), radius, true);

         // String potionSet, String playerSet
         pem.applySetToPlayers("explosion_potion_effects", "explosion_event");

      }
     
     
  3. > createPotionSet
    > creates ArrayList

    All jokes aside:
    • You should probably use a Set instead of a List.
    • Not all methods check for the existence of a key, which results in a NullPointerException
      • Instead, use computeIfAbsent to create the collection on-demand
      • This would also eliminate the need to use containsKey, or the need to call createFooSet manually
    • Use Map as field type, not HashMap (Liskov)
    • Instead of returning null, return an empty Collection (hint: Collections.emptyCollection())
    • Trust your code a bit more - especially when not doing so hurts performance for no good reason
      • You get an existing Collection, add another Collection to it, for some reason put it back (they're references, no need to call Map::put(Object, Object)), and even check if it was really added (and I can assure you, if you use ArrayList (or any List/Set for that matter), they will exist.
    • You use PotionEffectType::toString() as key rather than PotionEffectType::getName() - which you ironically checked for before. Typo?
    • Don't create new collections, just so you can iterate over them to do something with the contents. Just loop over all collections, and do the work on the spot.
     
    • Winner Winner x 1
  4. WAS

    WAS

    Thanks for the info. Most limitations are on effect of limitation of Java or Understanding of Java. As they improve, so does code. You are more then welcome to contribute to the code.

    For example, according to my understanding of the Collections extension, you can instantiate as a ArrayList

    emptyCollection() doesn't exist, so I assume another? List, Set? I'll do a set for now. Seems appropriate off the top of my head. And I'm not entirely sure how that is any different then creating a new ArrayList or a set.

    Won't pretend that a lot of what else you said makes sense. Maybe a little more explanation or source.
     
    #4 WAS, Apr 15, 2017
    Last edited: Apr 15, 2017
  5. this seems pretty cool if it would work haha
     
  6. WAS

    WAS

    Should work fine if you use it right. Lol Currently in use in Blast Radius. Should have another version which handles messages (and spam) soon.
     
  7. Why take a simple thing and make an API to make it equally simple with a huge added overhead.
     
  8. FrostedSnowman

    Resource Staff

    few things can be simplified / optimized to work with latest java builds, however, you forgot to handle this variable:

    'hasParsedConfig' in reset method. removing it is essentially the 'fix' but i assumed you wanted to do something with it?
     
  9. WAS

    WAS

    Oh yeah that's a remnant from the previous builds configuration ability.

    Also, I run the latest Java builds? And why make it only work for the latest builds?

    Made some changes to PEM2
     
    #9 WAS, Apr 15, 2017
    Last edited: Apr 15, 2017