Add NotifyBar and allow changing between color and style, fixes #433
This commit is contained in:
		| @@ -1,6 +1,7 @@ | |||||||
| package me.libraryaddict.disguise; | package me.libraryaddict.disguise; | ||||||
|  |  | ||||||
| import com.comphenix.protocol.wrappers.WrappedGameProfile; | import com.comphenix.protocol.wrappers.WrappedGameProfile; | ||||||
|  | import lombok.Getter; | ||||||
| import me.libraryaddict.disguise.disguisetypes.*; | import me.libraryaddict.disguise.disguisetypes.*; | ||||||
| import me.libraryaddict.disguise.disguisetypes.TargetedDisguise.TargetType; | import me.libraryaddict.disguise.disguisetypes.TargetedDisguise.TargetType; | ||||||
| import me.libraryaddict.disguise.disguisetypes.watchers.AbstractHorseWatcher; | import me.libraryaddict.disguise.disguisetypes.watchers.AbstractHorseWatcher; | ||||||
| @@ -24,10 +25,7 @@ import org.bukkit.potion.PotionEffectType; | |||||||
| import java.io.File; | import java.io.File; | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| import java.lang.reflect.Method; | import java.lang.reflect.Method; | ||||||
| import java.util.Arrays; | import java.util.*; | ||||||
| import java.util.Collection; |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.Map; |  | ||||||
|  |  | ||||||
| public class DisguiseAPI { | public class DisguiseAPI { | ||||||
|     private static int selfDisguiseId = ReflectionManager.getNewEntityId(true); |     private static int selfDisguiseId = ReflectionManager.getNewEntityId(true); | ||||||
|   | |||||||
| @@ -14,6 +14,8 @@ import me.libraryaddict.disguise.utilities.reflection.NmsVersion; | |||||||
| import me.libraryaddict.disguise.utilities.translations.LibsMsg; | import me.libraryaddict.disguise.utilities.translations.LibsMsg; | ||||||
| import me.libraryaddict.disguise.utilities.translations.TranslateType; | import me.libraryaddict.disguise.utilities.translations.TranslateType; | ||||||
| import org.bukkit.Bukkit; | import org.bukkit.Bukkit; | ||||||
|  | import org.bukkit.boss.BarColor; | ||||||
|  | import org.bukkit.boss.BarStyle; | ||||||
| import org.bukkit.command.CommandSender; | import org.bukkit.command.CommandSender; | ||||||
| import org.bukkit.configuration.ConfigurationSection; | import org.bukkit.configuration.ConfigurationSection; | ||||||
| import org.bukkit.configuration.file.YamlConfiguration; | import org.bukkit.configuration.file.YamlConfiguration; | ||||||
| @@ -211,7 +213,13 @@ public class DisguiseConfig { | |||||||
|     private static boolean retaliationCombat; |     private static boolean retaliationCombat; | ||||||
|     @Getter |     @Getter | ||||||
|     @Setter |     @Setter | ||||||
|     private static boolean notifyPlayerDisguised; |     private static NotifyBar notifyBar = NotifyBar.ACTION_BAR; | ||||||
|  |     @Getter | ||||||
|  |     @Setter | ||||||
|  |     private static BarStyle bossBarStyle = BarStyle.SOLID; | ||||||
|  |     @Getter | ||||||
|  |     @Setter | ||||||
|  |     private static BarColor bossBarColor = BarColor.GREEN; | ||||||
|     private static PermissionDefault commandVisibility = PermissionDefault.TRUE; |     private static PermissionDefault commandVisibility = PermissionDefault.TRUE; | ||||||
|  |  | ||||||
|     public static PermissionDefault getCommandVisibility() { |     public static PermissionDefault getCommandVisibility() { | ||||||
| @@ -385,7 +393,6 @@ public class DisguiseConfig { | |||||||
|         setMovementPacketsEnabled(config.getBoolean("PacketsEnabled.Movement")); |         setMovementPacketsEnabled(config.getBoolean("PacketsEnabled.Movement")); | ||||||
|         setNameAboveHeadAlwaysVisible(config.getBoolean("NameAboveHeadAlwaysVisible")); |         setNameAboveHeadAlwaysVisible(config.getBoolean("NameAboveHeadAlwaysVisible")); | ||||||
|         setNameOfPlayerShownAboveDisguise(config.getBoolean("ShowNamesAboveDisguises")); |         setNameOfPlayerShownAboveDisguise(config.getBoolean("ShowNamesAboveDisguises")); | ||||||
|         setNotifyPlayerDisguised(config.getBoolean("NotifyPlayerDisguised")); |  | ||||||
|         setPlayerDisguisesTablistExpires(config.getInt("PlayerDisguisesTablistExpires")); |         setPlayerDisguisesTablistExpires(config.getInt("PlayerDisguisesTablistExpires")); | ||||||
|         setPlayerHideArmor(config.getBoolean("PlayerHideArmor")); |         setPlayerHideArmor(config.getBoolean("PlayerHideArmor")); | ||||||
|         setRetaliationCombat(config.getBoolean("RetaliationCombat")); |         setRetaliationCombat(config.getBoolean("RetaliationCombat")); | ||||||
| @@ -412,6 +419,30 @@ public class DisguiseConfig { | |||||||
|             DisguiseUtilities.getLogger().warning("You must purchase the plugin to use saved disguises!"); |             DisguiseUtilities.getLogger().warning("You must purchase the plugin to use saved disguises!"); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             setNotifyBar(NotifyBar.valueOf(config.getString("NotifyBar").toUpperCase())); | ||||||
|  |         } | ||||||
|  |         catch (Exception ex) { | ||||||
|  |             DisguiseUtilities.getLogger() | ||||||
|  |                     .warning("Cannot parse '" + config.getString("NotifyBar") + "' to a valid option for NotifyBar"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             setBossBarColor(BarColor.valueOf(config.getString("BossBarColor").toUpperCase())); | ||||||
|  |         } | ||||||
|  |         catch (Exception ex) { | ||||||
|  |             DisguiseUtilities.getLogger().warning( | ||||||
|  |                     "Cannot parse '" + config.getString("BossBarColor") + "' to a valid option for BossBarColor"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             setBossBarStyle(BarStyle.valueOf(config.getString("BossBarStyle").toUpperCase())); | ||||||
|  |         } | ||||||
|  |         catch (Exception ex) { | ||||||
|  |             DisguiseUtilities.getLogger().warning( | ||||||
|  |                     "Cannot parse '" + config.getString("BossBarStyle") + "' to a valid option for BossBarStyle"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         try { |         try { | ||||||
|             setUpdatesBranch(UpdatesBranch.valueOf(config.getString("UpdatesBranch").toUpperCase())); |             setUpdatesBranch(UpdatesBranch.valueOf(config.getString("UpdatesBranch").toUpperCase())); | ||||||
|         } |         } | ||||||
| @@ -724,4 +755,12 @@ public class DisguiseConfig { | |||||||
|         SNAPSHOTS, |         SNAPSHOTS, | ||||||
|         RELEASES |         RELEASES | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public enum NotifyBar { | ||||||
|  |         NONE, | ||||||
|  |  | ||||||
|  |         BOSS_BAR, | ||||||
|  |  | ||||||
|  |         ACTION_BAR | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -9,6 +9,8 @@ import com.comphenix.protocol.wrappers.EnumWrappers.NativeGameMode; | |||||||
| import com.comphenix.protocol.wrappers.EnumWrappers.PlayerInfoAction; | import com.comphenix.protocol.wrappers.EnumWrappers.PlayerInfoAction; | ||||||
| import com.comphenix.protocol.wrappers.PlayerInfoData; | import com.comphenix.protocol.wrappers.PlayerInfoData; | ||||||
| import com.comphenix.protocol.wrappers.WrappedChatComponent; | import com.comphenix.protocol.wrappers.WrappedChatComponent; | ||||||
|  | import lombok.AccessLevel; | ||||||
|  | import lombok.Getter; | ||||||
| import me.libraryaddict.disguise.DisguiseAPI; | import me.libraryaddict.disguise.DisguiseAPI; | ||||||
| import me.libraryaddict.disguise.DisguiseConfig; | import me.libraryaddict.disguise.DisguiseConfig; | ||||||
| import me.libraryaddict.disguise.LibsDisguises; | import me.libraryaddict.disguise.LibsDisguises; | ||||||
| @@ -24,6 +26,10 @@ import net.md_5.bungee.api.ChatMessageType; | |||||||
| import net.md_5.bungee.api.chat.ComponentBuilder; | import net.md_5.bungee.api.chat.ComponentBuilder; | ||||||
| import org.bukkit.Bukkit; | import org.bukkit.Bukkit; | ||||||
| import org.bukkit.Location; | import org.bukkit.Location; | ||||||
|  | import org.bukkit.NamespacedKey; | ||||||
|  | import org.bukkit.boss.BarColor; | ||||||
|  | import org.bukkit.boss.BarStyle; | ||||||
|  | import org.bukkit.boss.BossBar; | ||||||
| import org.bukkit.entity.*; | import org.bukkit.entity.*; | ||||||
| import org.bukkit.metadata.FixedMetadataValue; | import org.bukkit.metadata.FixedMetadataValue; | ||||||
| import org.bukkit.scheduler.BukkitTask; | import org.bukkit.scheduler.BukkitTask; | ||||||
| @@ -61,6 +67,14 @@ public abstract class Disguise { | |||||||
|     private Runnable velocityRunnable; |     private Runnable velocityRunnable; | ||||||
|     private boolean velocitySent = DisguiseConfig.isVelocitySent(); |     private boolean velocitySent = DisguiseConfig.isVelocitySent(); | ||||||
|     private boolean viewSelfDisguise = DisguiseConfig.isViewDisguises(); |     private boolean viewSelfDisguise = DisguiseConfig.isViewDisguises(); | ||||||
|  |     @Getter | ||||||
|  |     private DisguiseConfig.NotifyBar notifyBar = DisguiseConfig.getNotifyBar(); | ||||||
|  |     @Getter | ||||||
|  |     private BarColor bossBarColor = DisguiseConfig.getBossBarColor(); | ||||||
|  |     @Getter | ||||||
|  |     private BarStyle bossBarStyle = DisguiseConfig.getBossBarStyle(); | ||||||
|  |     @Getter(value = AccessLevel.PRIVATE) | ||||||
|  |     private final NamespacedKey bossBar = new NamespacedKey(LibsDisguises.getInstance(), UUID.randomUUID().toString()); | ||||||
|     private FlagWatcher watcher; |     private FlagWatcher watcher; | ||||||
|     /** |     /** | ||||||
|      * If set, how long before disguise expires |      * If set, how long before disguise expires | ||||||
| @@ -131,6 +145,64 @@ public abstract class Disguise { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public void setNotifyBar(DisguiseConfig.NotifyBar bar) { | ||||||
|  |         if (getNotifyBar() == bar) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (getNotifyBar() == DisguiseConfig.NotifyBar.BOSS_BAR) { | ||||||
|  |             Bukkit.removeBossBar(getBossBar()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this.notifyBar = bar; | ||||||
|  |  | ||||||
|  |         makeBossBar(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void setBossBarColor(BarColor color) { | ||||||
|  |         if (getBossBarColor() == color) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this.bossBarColor = color; | ||||||
|  |  | ||||||
|  |         makeBossBar(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void setBossBarStyle(BarStyle style) { | ||||||
|  |         if (getBossBarStyle() == style) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this.bossBarStyle = style; | ||||||
|  |  | ||||||
|  |         makeBossBar(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void setBossBar(BarColor color, BarStyle style) { | ||||||
|  |         this.bossBarColor = color; | ||||||
|  |         this.bossBarStyle = style; | ||||||
|  |  | ||||||
|  |         setNotifyBar(DisguiseConfig.NotifyBar.BOSS_BAR); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void makeBossBar() { | ||||||
|  |         if (getNotifyBar() != DisguiseConfig.NotifyBar.BOSS_BAR || !(getEntity() instanceof Player)) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (getEntity().hasPermission("libsdisguises.noactionbar") || DisguiseAPI.getDisguise(getEntity()) != this) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         Bukkit.removeBossBar(getBossBar()); | ||||||
|  |  | ||||||
|  |         BossBar bar = Bukkit | ||||||
|  |                 .createBossBar(getBossBar(), LibsMsg.ACTION_BAR_MESSAGE.get(getType().toReadable()), getBossBarColor(), | ||||||
|  |                         getBossBarStyle()); | ||||||
|  |         bar.addPlayer((Player) getEntity()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     private void createRunnable() { |     private void createRunnable() { | ||||||
|         final boolean alwaysSendVelocity; |         final boolean alwaysSendVelocity; | ||||||
|  |  | ||||||
| @@ -174,7 +246,7 @@ public abstract class Disguise { | |||||||
|                 if (++actionBarTicks % 15 == 0) { |                 if (++actionBarTicks % 15 == 0) { | ||||||
|                     actionBarTicks = 0; |                     actionBarTicks = 0; | ||||||
|  |  | ||||||
|                     if (DisguiseConfig.isNotifyPlayerDisguised() && getEntity() instanceof Player && |                     if (getNotifyBar() == DisguiseConfig.NotifyBar.ACTION_BAR && getEntity() instanceof Player && | ||||||
|                             !getEntity().hasPermission("libsdisguises.noactionbar") && |                             !getEntity().hasPermission("libsdisguises.noactionbar") && | ||||||
|                             DisguiseAPI.getDisguise(getEntity()) == Disguise.this) { |                             DisguiseAPI.getDisguise(getEntity()) == Disguise.this) { | ||||||
|                         ((Player) getEntity()).spigot().sendMessage(ChatMessageType.ACTION_BAR, |                         ((Player) getEntity()).spigot().sendMessage(ChatMessageType.ACTION_BAR, | ||||||
| @@ -744,6 +816,11 @@ public abstract class Disguise { | |||||||
|         getEntity().setMetadata("LastDisguise", |         getEntity().setMetadata("LastDisguise", | ||||||
|                 new FixedMetadataValue(LibsDisguises.getInstance(), System.currentTimeMillis())); |                 new FixedMetadataValue(LibsDisguises.getInstance(), System.currentTimeMillis())); | ||||||
|  |  | ||||||
|  |         if (getNotifyBar() == DisguiseConfig.NotifyBar.BOSS_BAR && getEntity() instanceof Player && | ||||||
|  |                 !getEntity().hasPermission("libsdisguises.noactionbar")) { | ||||||
|  |             Bukkit.removeBossBar(getBossBar()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -943,6 +1020,8 @@ public abstract class Disguise { | |||||||
|                     System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(330)); |                     System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(330)); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         makeBossBar(); | ||||||
|  |  | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| package me.libraryaddict.disguise.utilities.params; | package me.libraryaddict.disguise.utilities.params; | ||||||
|  |  | ||||||
| import lombok.Getter; | import lombok.Getter; | ||||||
|  | import me.libraryaddict.disguise.DisguiseConfig; | ||||||
| import me.libraryaddict.disguise.disguisetypes.Disguise; | import me.libraryaddict.disguise.disguisetypes.Disguise; | ||||||
| import me.libraryaddict.disguise.disguisetypes.DisguiseType; | import me.libraryaddict.disguise.disguisetypes.DisguiseType; | ||||||
| import me.libraryaddict.disguise.disguisetypes.FlagWatcher; | import me.libraryaddict.disguise.disguisetypes.FlagWatcher; | ||||||
| @@ -12,6 +13,8 @@ import me.libraryaddict.disguise.utilities.params.types.custom.ParamInfoItemBloc | |||||||
| import me.libraryaddict.disguise.utilities.parser.DisguisePerm; | import me.libraryaddict.disguise.utilities.parser.DisguisePerm; | ||||||
| import me.libraryaddict.disguise.utilities.watchers.DisguiseMethods; | import me.libraryaddict.disguise.utilities.watchers.DisguiseMethods; | ||||||
| import org.bukkit.ChatColor; | import org.bukkit.ChatColor; | ||||||
|  | import org.bukkit.boss.BarColor; | ||||||
|  | import org.bukkit.boss.BarStyle; | ||||||
| import org.bukkit.inventory.ItemStack; | import org.bukkit.inventory.ItemStack; | ||||||
|  |  | ||||||
| import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||||
| @@ -110,10 +113,29 @@ public class ParamInfoManager { | |||||||
|  |  | ||||||
|         // Add these last as it's what we want to present to be called the least |         // Add these last as it's what we want to present to be called the least | ||||||
|         for (String methodName : new String[]{"setSelfDisguiseVisible", "setHideHeldItemFromSelf", |         for (String methodName : new String[]{"setSelfDisguiseVisible", "setHideHeldItemFromSelf", | ||||||
|                 "setHideArmorFromSelf", "setHearSelfDisguise", "setHidePlayer", "setExpires"}) { |                 "setHideArmorFromSelf", "setHearSelfDisguise", "setHidePlayer", "setExpires", "setNotifyBar", | ||||||
|  |                 "setBossBarColor", "setBossBarStyle"}) { | ||||||
|             try { |             try { | ||||||
|                 methods.add(Disguise.class |                 Class cl = boolean.class; | ||||||
|                         .getMethod(methodName, methodName.equals("setExpires") ? long.class : boolean.class)); |  | ||||||
|  |                 switch (methodName) { | ||||||
|  |                     case "setExpires": | ||||||
|  |                         cl = long.class; | ||||||
|  |                         break; | ||||||
|  |                     case "setNotifyBar": | ||||||
|  |                         cl = DisguiseConfig.NotifyBar.class; | ||||||
|  |                         break; | ||||||
|  |                     case "setBossBarColor": | ||||||
|  |                         cl = BarColor.class; | ||||||
|  |                         break; | ||||||
|  |                     case "setBossBarStyle": | ||||||
|  |                         cl = BarStyle.class; | ||||||
|  |                         break; | ||||||
|  |                     default: | ||||||
|  |                         break; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 methods.add(Disguise.class.getMethod(methodName, cl)); | ||||||
|             } |             } | ||||||
|             catch (Exception ex) { |             catch (Exception ex) { | ||||||
|                 ex.printStackTrace(); |                 ex.printStackTrace(); | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ package me.libraryaddict.disguise.utilities.params; | |||||||
| import com.comphenix.protocol.wrappers.BlockPosition; | import com.comphenix.protocol.wrappers.BlockPosition; | ||||||
| import com.comphenix.protocol.wrappers.WrappedGameProfile; | import com.comphenix.protocol.wrappers.WrappedGameProfile; | ||||||
| import com.comphenix.protocol.wrappers.WrappedParticle; | import com.comphenix.protocol.wrappers.WrappedParticle; | ||||||
|  | import me.libraryaddict.disguise.DisguiseConfig; | ||||||
| import me.libraryaddict.disguise.disguisetypes.EntityPose; | import me.libraryaddict.disguise.disguisetypes.EntityPose; | ||||||
| import me.libraryaddict.disguise.disguisetypes.RabbitType; | import me.libraryaddict.disguise.disguisetypes.RabbitType; | ||||||
| import me.libraryaddict.disguise.utilities.params.types.ParamInfoEnum; | import me.libraryaddict.disguise.utilities.params.types.ParamInfoEnum; | ||||||
| @@ -12,6 +13,8 @@ import me.libraryaddict.disguise.utilities.reflection.NmsVersion; | |||||||
| import org.apache.commons.lang.StringUtils; | import org.apache.commons.lang.StringUtils; | ||||||
| import org.bukkit.*; | import org.bukkit.*; | ||||||
| import org.bukkit.block.BlockFace; | import org.bukkit.block.BlockFace; | ||||||
|  | import org.bukkit.boss.BarColor; | ||||||
|  | import org.bukkit.boss.BarStyle; | ||||||
| import org.bukkit.entity.*; | import org.bukkit.entity.*; | ||||||
| import org.bukkit.inventory.ItemStack; | import org.bukkit.inventory.ItemStack; | ||||||
| import org.bukkit.inventory.MainHand; | import org.bukkit.inventory.MainHand; | ||||||
| @@ -87,6 +90,11 @@ public class ParamInfoTypes { | |||||||
|                     "The different variants for mushroom cows")); |                     "The different variants for mushroom cows")); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         paramInfos.add(new ParamInfoEnum(DisguiseConfig.NotifyBar.class, "NotifyBar", | ||||||
|  |                 "Where the disguised indicator should appear")); | ||||||
|  |         paramInfos.add(new ParamInfoEnum(BarColor.class, "BarColor", "The color of the boss bar")); | ||||||
|  |         paramInfos.add(new ParamInfoEnum(BarStyle.class, "BarStyle", "The style of the boss bar")); | ||||||
|  |  | ||||||
|         // Register custom types |         // Register custom types | ||||||
|         paramInfos.add(new ParamInfoEulerAngle(EulerAngle.class, "Euler Angle", "Euler Angle (X,Y,Z)", |         paramInfos.add(new ParamInfoEulerAngle(EulerAngle.class, "Euler Angle", "Euler Angle (X,Y,Z)", | ||||||
|                 "Set the X,Y,Z directions on an armorstand")); |                 "Set the X,Y,Z directions on an armorstand")); | ||||||
|   | |||||||
| @@ -120,9 +120,15 @@ DisguiseSounds: true | |||||||
| # I disable this as it can be a little confusing when not used with self disguises | # I disable this as it can be a little confusing when not used with self disguises | ||||||
| HearSelfDisguise: true | HearSelfDisguise: true | ||||||
|  |  | ||||||
| # When disguised, should a message be displayed to the player in action bar? | # When disguised, should a message be displayed to the player? If so, where? | ||||||
| # The message can be customized in translations | # The message can be customized in translations | ||||||
| NotifyPlayerDisguised: true | # NONE, BOSS_BAR, ACTION_BAR | ||||||
|  | NotifyBar: ACTION_BAR | ||||||
|  | # If using boss bar, these two options come into play | ||||||
|  | # https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/boss/BarColor.html | ||||||
|  | BossBarColor: GREEN | ||||||
|  | # https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/boss/BarStyle.html | ||||||
|  | BossBarStyle: SOLID | ||||||
|  |  | ||||||
| # Shall I send the velocity packets? I REALLY recommend you don't disable. | # Shall I send the velocity packets? I REALLY recommend you don't disable. | ||||||
| # This is the only thing allowing the mobs to fly without glitching out. | # This is the only thing allowing the mobs to fly without glitching out. | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user