1010import org .bukkit .potion .PotionEffect ;
1111import org .bukkit .potion .PotionEffectType ;
1212import org .bukkit .scheduler .BukkitRunnable ;
13+ import org .jetbrains .annotations .NotNull ;
14+ import org .jetbrains .annotations .Nullable ;
1315
1416import java .util .*;
1517import java .util .concurrent .CompletableFuture ;
1618
19+ /**
20+ * The manager that takes care of masks. Masks are heads that when worn, give players certain effects. This manager
21+ * allows external plugins to access and register their own masks.
22+ *
23+ * @author Thatsmusic99 (Holly)
24+ */
1725public class MaskManager {
1826
1927 private final HashMap <String , MaskInfo > masks = new HashMap <>();
@@ -25,54 +33,120 @@ private MaskManager(boolean empty) {
2533 if (!empty ) init ();
2634 }
2735
36+ /**
37+ * Initiates the mask manager. Not intended for external use.
38+ */
2839 public MaskManager () {
2940 this (false );
3041 }
3142
43+ /**
44+ * Retrieves an instance of the Mask Manager. If an instance does not already exist, one will be created.
45+ *
46+ * @return the existing instance of the mask manager.
47+ */
48+ @ NotNull
3249 public static MaskManager get () {
3350 if (instance == null ) instance = new MaskManager (true );
3451 return instance ;
3552 }
3653
54+ /**
55+ * The method used to re-register masks in the configuration file. Any head added via an API will be lost.
56+ */
3757 public void reload () {
3858 reset ();
3959 init ();
4060 }
4161
42- public void resetMask (Player player ) {
62+ /**
63+ * Removes the mask effects from a specific player.
64+ *
65+ * @param player the player to have the mask effects reset.
66+ */
67+ public void resetMask (@ NotNull Player player ) {
68+ Objects .requireNonNull (player , "The player specified is null!" );
69+
70+ // If the player does not have an active mask, stop there.
4371 if (!runningTasks .containsKey (player .getUniqueId ().toString ())) return ;
72+
73+ // Cancel the runnable controlling the masks.
4474 runningTasks .get (player .getUniqueId ().toString ()).cancel ();
4575 }
4676
77+ /**
78+ * Clears all registered masks and stops all running ones.
79+ */
4780 public void reset () {
4881 masks .clear ();
4982 runningTasks .values ().forEach (BukkitRunnable ::cancel );
5083 runningTasks .clear ();
5184 }
5285
53- public void registerMask (String key , MaskInfo headInfo ) {
54- masks .put (key , headInfo );
86+ /**
87+ * Registers a mask with an ID and its mask data.
88+ *
89+ * @param key The ID of the mask to be specified. It does not require the HPM# prefix.
90+ * @param maskInfo The mask data in question.
91+ * @throws IllegalStateException if the mask with the specific ID has already been registered.
92+ */
93+ public void registerMask (@ NotNull String key , @ NotNull MaskInfo maskInfo ) {
94+
95+ // Make sure nothing is null
96+ Objects .requireNonNull (key , "The key to be used is null!" );
97+ Objects .requireNonNull (maskInfo , "The mask data is null!" );
98+
99+ // If the key includes HPM#, remove it.
100+ key = removeMaskPrefix (key );
101+
102+ // If the mask has already been registered, stop it there
103+ if (isMaskRegistered (key )) {
104+ throw new IllegalStateException ("The mask " + key + " has already been registered!" );
105+ }
106+
107+ // Register the mask!
108+ masks .put (key , maskInfo );
55109 }
56110
57- public MaskInfo getMaskInfo (String key ) {
58- if (key .startsWith ("HPM#" )) {
59- key = key .substring (4 );
60- }
61- return (MaskInfo ) masks .getOrDefault (key , new MaskInfo ()).clone ();
111+ /**
112+ * Gets the mask data of a mask with a specific ID. The mask data in question is cloned, so it is used per-player.
113+ *
114+ * @param key The ID of the mask. It can contain the HPM# prefix, but HP# will potentially return null.
115+ * @return The mask data of the mask if it is registered. If it is not registered, then null is returned instead.
116+ */
117+ @ Nullable
118+ public MaskInfo getMaskInfo (@ NotNull String key ) {
119+
120+ // Make sure nothing is null
121+ Objects .requireNonNull (key , "The key used to search for a mask is null!" );
122+
123+ // Get the mask information with the specified character.
124+ MaskInfo info = masks .get (removeMaskPrefix (key ));
125+ if (info == null ) return null ;
126+ return (MaskInfo ) info .clone ();
62127 }
63128
129+ /**
130+ * Determines whether a mask with a specified ID is registered.
131+ *
132+ * @param key The key of the mask to be checked.
133+ * @return true if the mask is registered, false if it is not.
134+ */
64135 public boolean isMaskRegistered (String key ) {
65- if (key .startsWith ("HPM#" )) {
66- key = key .substring (4 );
67- }
68- return masks .containsKey (key );
136+ return masks .containsKey (removeMaskPrefix (key ));
69137 }
70138
139+ /**
140+ * A set of all masks that have been registered. The set in question is cloned, so modifying it has no effect on the
141+ * actual masks map.
142+ *
143+ * @return A set of all mask IDs.
144+ */
71145 public Set <String > getMaskKeys () {
72- return masks .keySet ();
146+ return new HashSet <>( masks .keySet () );
73147 }
74148
75- public void init () {
149+ private void init () {
76150 ConfigMasks masksConfig = ConfigMasks .get ();
77151 // Get the config section
78152 ConfigSection masksSection = masksConfig .getConfigSection ("masks" );
@@ -125,14 +199,34 @@ public void init() {
125199 HeadsPlus .get ().getLogger ().info ("Registered " + masks .size () + " masks." );
126200 }
127201
202+ private String removeMaskPrefix (String key ) {
203+ if (key .startsWith ("HPM#" )) {
204+ key = key .substring (4 );
205+ }
206+ return key ;
207+ }
208+
209+ /**
210+ * A base class representing masks. It inherits {@link HeadManager.HeadInfo}, so item metadata is stored there.
211+ * Actual mask functions are handled within this class.
212+ */
128213 public static class MaskInfo extends HeadManager .HeadInfo {
129214
130215 protected String id ;
131216
217+ /**
218+ * Initialises an empty mask without an ID.
219+ */
132220 public MaskInfo () {
133221 super ();
134222 }
135223
224+ /**
225+ * Initialises a mask with existing head info, and its own ID.
226+ *
227+ * @param info The head info to be adopted by the mask.
228+ * @param id The ID for the head.
229+ */
136230 public MaskInfo (HeadManager .HeadInfo info , String id ) {
137231 super ();
138232 this .id = id ;
@@ -142,7 +236,33 @@ public MaskInfo(HeadManager.HeadInfo info, String id) {
142236 withMaterial (info .getMaterial ());
143237 }
144238
145- public void run (Player player ) {
239+ /**
240+ * Prompts the mask functions to start with a specified player.
241+ *
242+ * @param player The player using the mask.
243+ */
244+ public void run (@ NotNull Player player ) {
245+ }
246+
247+ /**
248+ * Determines whether a specified player is still wearing the mask and is able to.
249+ *
250+ * @param player The player in question
251+ * @return true if the mask effects can persist, or false if the player isn't wearing the mask, or if the
252+ * effects should not apply.
253+ */
254+ public boolean isMaskBeingWorn (@ Nullable Player player ) {
255+ // If the player is null, offline or if masks are disabled, stop there
256+ if (player == null || !player .isOnline () || !MainConfig .get ().getMainFeatures ().MASKS ) {
257+ return false ;
258+ }
259+ // Get the helmet and ensure it is a valid mask
260+ ItemStack helmet = player .getInventory ().getHelmet ();
261+ if (helmet == null || !PersistenceManager .get ().getMaskType (helmet ).equals (id )) {
262+ return false ;
263+ }
264+ // Make sure WorldGuard is not blocking effects
265+ return !HeadsPlus .get ().canUseWG () || FlagHandler .canUseMasks (player );
146266 }
147267
148268 @ Override
@@ -167,6 +287,9 @@ public ItemStack forceBuildHead() {
167287 }
168288 }
169289
290+ /**
291+ * Represents a mask that applies potion effects to a player when worn.
292+ */
170293 public class PotionMask extends MaskInfo {
171294
172295 private List <PotionEffect > effects ;
@@ -187,24 +310,15 @@ public PotionMask addEffect(PotionEffect effect) {
187310 }
188311
189312 @ Override
190- public void run (Player player ) {
313+ public void run (@ NotNull Player player ) {
191314 BukkitRunnable runnable = new BukkitRunnable () {
192315
193316 private int intervals = MainConfig .get ().getMasks ().RESET_INTERVAL - 1 ;
194317
195318 @ Override
196319 public void run () {
197- if (player == null || !player .isOnline () || !MainConfig .get ().getMainFeatures ().MASKS ) {
198- cancel ();
199- return ;
200- }
201- // Get the helmet
202- ItemStack helmet = player .getInventory ().getHelmet ();
203- if (helmet == null || !PersistenceManager .get ().getMaskType (helmet ).equals (id )) {
204- cancel ();
205- return ;
206- }
207- if (HeadsPlus .get ().canUseWG () && !FlagHandler .canUseMasks (player )) {
320+ // If the mask isn't being worn, stop there and cancel the mask
321+ if (!isMaskBeingWorn (player )) {
208322 cancel ();
209323 return ;
210324 }
0 commit comments