547 lines
20 KiB
Java
547 lines
20 KiB
Java
/*
|
|
* Copyright (c) 2018 univento.eu - All rights reserved
|
|
* You are not allowed to use, distribute or modify this code
|
|
*/
|
|
|
|
package eu.univento.core.api.player;
|
|
|
|
import com.google.common.io.ByteArrayDataOutput;
|
|
import com.google.common.io.ByteStreams;
|
|
import com.mojang.authlib.GameProfile;
|
|
import eu.univento.commons.player.DatabasePlayer;
|
|
import eu.univento.commons.player.language.MessageConstant;
|
|
import eu.univento.commons.player.rank.Rank;
|
|
import eu.univento.commons.player.warn.WarnReason;
|
|
import eu.univento.commons.server.ServerType;
|
|
import eu.univento.core.Core;
|
|
import eu.univento.core.api.Hologram;
|
|
import eu.univento.core.api.chat.DefaultFontInfo;
|
|
import eu.univento.core.api.effects.Blackscreen;
|
|
import eu.univento.core.api.effects.Effects;
|
|
import eu.univento.core.api.gui.hologram.HologramData;
|
|
import eu.univento.core.api.quest.Quest;
|
|
import eu.univento.core.api.server.ServerSettings;
|
|
import io.netty.buffer.ByteBuf;
|
|
import io.netty.buffer.Unpooled;
|
|
import io.vertx.core.json.JsonObject;
|
|
import lombok.Getter;
|
|
import lombok.Setter;
|
|
import net.md_5.bungee.api.chat.TextComponent;
|
|
import net.minecraft.server.v1_12_R1.*;
|
|
import org.bukkit.*;
|
|
import org.bukkit.attribute.Attribute;
|
|
import org.bukkit.attribute.AttributeInstance;
|
|
import org.bukkit.attribute.AttributeModifier;
|
|
import org.bukkit.block.Chest;
|
|
import org.bukkit.block.DoubleChest;
|
|
import org.bukkit.block.EnderChest;
|
|
import org.bukkit.block.ShulkerBox;
|
|
import org.bukkit.boss.BarColor;
|
|
import org.bukkit.boss.BarFlag;
|
|
import org.bukkit.boss.BarStyle;
|
|
import org.bukkit.boss.BossBar;
|
|
import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
|
|
import org.bukkit.craftbukkit.v1_12_R1.CraftWorld;
|
|
import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer;
|
|
import org.bukkit.craftbukkit.v1_12_R1.inventory.CraftItemStack;
|
|
import org.bukkit.entity.Player;
|
|
import org.bukkit.inventory.ItemStack;
|
|
import org.bukkit.potion.PotionEffect;
|
|
import org.bukkit.scoreboard.Scoreboard;
|
|
import org.bukkit.scoreboard.Team;
|
|
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.ObjectOutputStream;
|
|
import java.lang.reflect.Field;
|
|
import java.time.Instant;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
import java.util.UUID;
|
|
import java.util.concurrent.CompletableFuture;
|
|
|
|
public class CustomPlayer extends CraftPlayer {
|
|
|
|
private static final HashMap<UUID, CustomPlayer> PLAYERS = new HashMap<>();
|
|
private static final Map<UUID, NickedPlayer> nickedPlayers = new HashMap<>();
|
|
private final Player PLAYER;
|
|
private final DatabasePlayer DATABASE_PLAYER;
|
|
|
|
@Getter @Setter private boolean openInventory;
|
|
|
|
private final GameProfile gameProfile;
|
|
|
|
@Getter private HologramData hologramData;
|
|
|
|
private CustomPlayer(Player player) {
|
|
super((CraftServer) Bukkit.getServer(), ((CraftPlayer) player).getHandle());
|
|
DATABASE_PLAYER = new DatabasePlayer(player.getUniqueId());
|
|
PLAYERS.put(player.getUniqueId(), this);
|
|
PLAYER = player;
|
|
gameProfile = ((CraftPlayer) player).getProfile();
|
|
hologramData = new HologramData(this);
|
|
}
|
|
|
|
public void onLeave() {
|
|
DATABASE_PLAYER.setInDatabase("lastOnline", Instant.now().toString());
|
|
|
|
HashMap<String, Object> location = new HashMap<>();
|
|
location.put("X", getLocation().getX());
|
|
location.put("Y", getLocation().getY());
|
|
location.put("Z", getLocation().getZ());
|
|
location.put("Yaw", String.valueOf(getLocation().getYaw()));
|
|
location.put("Pitch", String.valueOf(getLocation().getPitch()));
|
|
|
|
if (ServerSettings.isLobby()) DATABASE_PLAYER.setInDatabase("Pos", location);
|
|
|
|
if (PLAYERS.containsKey(getUniqueId())) PLAYERS.remove(getUniqueId());
|
|
getDatabasePlayer().save();
|
|
}
|
|
|
|
public static CustomPlayer getPlayer(String player) {
|
|
if (Bukkit.getPlayer(player) == null) return null;
|
|
Player p = Bukkit.getPlayer(player);
|
|
if (PLAYERS.containsKey(p.getUniqueId())) {
|
|
return PLAYERS.get(p.getUniqueId());
|
|
} else {
|
|
return new CustomPlayer(p);
|
|
}
|
|
}
|
|
|
|
public static CustomPlayer getPlayer(UUID player) {
|
|
if (PLAYERS.containsKey(player)) {
|
|
return PLAYERS.get(player);
|
|
} else {
|
|
Player p = Bukkit.getPlayer(player);
|
|
return p == null ? null : new CustomPlayer(p);
|
|
}
|
|
}
|
|
|
|
public static CustomPlayer getPlayer(Player player) {
|
|
return getPlayer(player.getUniqueId());
|
|
}
|
|
|
|
public Player getPlayer() {
|
|
return PLAYER;
|
|
}
|
|
|
|
public DatabasePlayer getDatabasePlayer() {
|
|
return DATABASE_PLAYER;
|
|
}
|
|
|
|
/*
|
|
Chat
|
|
*/
|
|
|
|
public void sendMessage(MessageConstant constant) {
|
|
sendMessage(ChatColor.translateAlternateColorCodes('&', getDatabasePlayer().getLanguage().getMessage(constant)));
|
|
}
|
|
|
|
public void sendCentredMessage(String message) {
|
|
if (message == null || message.equals("")) {
|
|
sendMessage("");
|
|
return;
|
|
}
|
|
message = ChatColor.translateAlternateColorCodes('&', message);
|
|
|
|
int messagePxSize = 0;
|
|
boolean previousCode = false;
|
|
boolean isBold = false;
|
|
|
|
for (char c : message.toCharArray()) {
|
|
if (c == '§') {
|
|
previousCode = true;
|
|
} else if (previousCode) {
|
|
previousCode = false;
|
|
isBold = c == 'l' || c == 'L';
|
|
} else {
|
|
DefaultFontInfo dFI = DefaultFontInfo.getDefaultFontInfo(c);
|
|
messagePxSize += isBold ? dFI.getBoldLength() : dFI.getLength();
|
|
messagePxSize++;
|
|
}
|
|
}
|
|
int CENTER_PX = 154;
|
|
int halvedMessageSize = messagePxSize / 2;
|
|
int toCompensate = CENTER_PX - halvedMessageSize;
|
|
int spaceLength = DefaultFontInfo.SPACE.getLength() + 1;
|
|
int compensated = 0;
|
|
StringBuilder sb = new StringBuilder();
|
|
while (compensated < toCompensate) {
|
|
sb.append(" ");
|
|
compensated += spaceLength;
|
|
}
|
|
sendMessage(sb.toString() + message);
|
|
}
|
|
|
|
/*
|
|
Graphical User Interface
|
|
*/
|
|
|
|
public void sendActionBar(String text) {
|
|
IChatBaseComponent cbc = IChatBaseComponent.ChatSerializer.a("{\"text\": \"" + text + "\"}");
|
|
PacketPlayOutChat ppoc = new PacketPlayOutChat(cbc, ChatMessageType.a((byte) 2));
|
|
sendPacket(ppoc);
|
|
}
|
|
|
|
public void sendTitle(int fadeIn, int stay, int fadeOut, String title, String subtitle) {
|
|
PacketPlayOutTitle packetPlayOutTimes = new PacketPlayOutTitle(PacketPlayOutTitle.EnumTitleAction.TIMES, null, fadeIn, stay, fadeOut);
|
|
sendPacket(packetPlayOutTimes);
|
|
|
|
if (subtitle != null) {
|
|
subtitle = ChatColor.translateAlternateColorCodes('&', subtitle);
|
|
IChatBaseComponent titleSub = IChatBaseComponent.ChatSerializer.a("{\"text\": \"" + subtitle + "\"}");
|
|
PacketPlayOutTitle packetPlayOutSubTitle = new PacketPlayOutTitle(PacketPlayOutTitle.EnumTitleAction.SUBTITLE, titleSub);
|
|
sendPacket(packetPlayOutSubTitle);
|
|
}
|
|
|
|
if (title != null) {
|
|
title = ChatColor.translateAlternateColorCodes('&', title);
|
|
IChatBaseComponent titleMain = IChatBaseComponent.ChatSerializer.a("{\"text\": \"" + title + "\"}");
|
|
PacketPlayOutTitle packetPlayOutTitle = new PacketPlayOutTitle(PacketPlayOutTitle.EnumTitleAction.TITLE, titleMain);
|
|
sendPacket(packetPlayOutTitle);
|
|
}
|
|
}
|
|
|
|
public BossBar sendBossBar(String text, BarColor color, BarStyle style, BarFlag flag) {
|
|
BossBar bar = Bukkit.createBossBar(text, color, style, flag);
|
|
bar.addPlayer(PLAYER);
|
|
return bar;
|
|
}
|
|
|
|
@Deprecated
|
|
public Hologram sendHologram(ItemStack item, Location location, String... text) {
|
|
Hologram hologram = new Hologram(item, text, location);
|
|
hologram.showPlayer(this);
|
|
return hologram;
|
|
}
|
|
|
|
public void sendTabHeaderAndFooter(String header, String footer) {
|
|
if (header == null)
|
|
header = "";
|
|
header = ChatColor.translateAlternateColorCodes('&', header);
|
|
|
|
if (footer == null)
|
|
footer = "";
|
|
footer = ChatColor.translateAlternateColorCodes('&', footer);
|
|
|
|
header = header.replaceAll("%player%", getDisplayName());
|
|
footer = footer.replaceAll("%player%", getDisplayName());
|
|
PLAYER.setPlayerListHeaderFooter(new TextComponent(header), new TextComponent(footer));
|
|
|
|
}
|
|
|
|
/*
|
|
Cloud
|
|
*/
|
|
|
|
public void connectToServer(String server) {
|
|
ByteArrayDataOutput out = ByteStreams.newDataOutput();
|
|
out.writeUTF("Connect");
|
|
out.writeUTF(server);
|
|
sendPluginMessage(Core.getInstance(), "BungeeCord", out.toByteArray());
|
|
}
|
|
|
|
public void connectToServer(ServerType type) {
|
|
Core.getCloudAPI().getOptimalServer(this, type).whenComplete((s, throwable) -> connectToServer(s));
|
|
}
|
|
|
|
/*
|
|
Inventory
|
|
*/
|
|
|
|
public boolean hasEmptyInventory() {
|
|
return getInventory().firstEmpty() != -1;
|
|
}
|
|
|
|
/*
|
|
Effects
|
|
*/
|
|
|
|
/**
|
|
* @param location location for effect
|
|
* @param effect particle effect
|
|
* @param id the id
|
|
* @param data the data
|
|
* @param offsetX offset in x direction
|
|
* @param offsetY offset in y direction
|
|
* @param offsetZ offset in z direction
|
|
* @param speed particle speed
|
|
* @param particleCount count of showed particles
|
|
* @param radius effect radius
|
|
*/
|
|
public void playEffect(Location location, Effect effect, int id, int data, float offsetX, float offsetY, float offsetZ, float speed, int particleCount, int radius) {
|
|
if (DATABASE_PLAYER.getSettings().hasEffectsEnabled()) {
|
|
PLAYER.spigot().playEffect(location, effect, id, data, offsetX, offsetY, offsetZ, speed, particleCount, radius);
|
|
}
|
|
}
|
|
|
|
@Deprecated
|
|
public void playParticle(Location loc, EnumParticle ep, float f, int count) {
|
|
if (DATABASE_PLAYER.getSettings().hasEffectsEnabled()) Effects.playEffectToPlayer(PLAYER, loc, ep, f, count);
|
|
}
|
|
|
|
/*
|
|
Combat
|
|
*/
|
|
public void setAttackSpeed(double speed) {
|
|
AttributeModifier modifier = new AttributeModifier(Core.getInstance().getName(), speed, AttributeModifier.Operation.ADD_NUMBER);
|
|
getAttribute(Attribute.GENERIC_ATTACK_SPEED).addModifier(modifier);
|
|
}
|
|
|
|
private double getAttackSpeed() {
|
|
return getAttribute(Attribute.GENERIC_ATTACK_SPEED).getValue();
|
|
}
|
|
|
|
public void resetAttackSpeed() {
|
|
AttributeModifier modifier = new AttributeModifier(Core.getInstance().getName(), getAttackSpeed(), AttributeModifier.Operation.ADD_NUMBER);
|
|
getAttribute(Attribute.GENERIC_ATTACK_SPEED).removeModifier(modifier);
|
|
AttributeInstance instance = getAttribute(Attribute.GENERIC_ATTACK_SPEED);
|
|
instance.setBaseValue(16.0D);
|
|
}
|
|
|
|
/*
|
|
Nick
|
|
*/
|
|
|
|
public void setNickName(String name) {
|
|
if (name.length() > 16) {
|
|
sendMessage("Disguised name can only be less the 16 characters.");
|
|
return;
|
|
}
|
|
if (isNicked()) {
|
|
sendMessage("You are already disguised!");
|
|
return;
|
|
}
|
|
if (Bukkit.getOnlinePlayers().stream().filter(p -> p.getName().equals(name)).count() != 0) {
|
|
sendMessage("The name you chose is already online.");
|
|
return;
|
|
}
|
|
nickedPlayers.put(getUniqueId(), new NickedPlayer(this, name));
|
|
setGameProfile(name, new GameProfile(getUniqueId(), name));
|
|
}
|
|
|
|
private void setGameProfile(String name, GameProfile profile) {
|
|
getHandle().playerConnection.sendPacket(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, getHandle()));
|
|
setDisplayName(name);
|
|
setPlayerListName(name);
|
|
try {
|
|
Field gp2 = getHandle().getClass().getSuperclass().getDeclaredField("bT");
|
|
gp2.setAccessible(true);
|
|
gp2.set(getHandle(), profile);
|
|
gp2.setAccessible(false);
|
|
} catch (Exception e) {
|
|
e.printStackTrace();
|
|
removeNickName();
|
|
return;
|
|
}
|
|
Core.getOnlinePlayers().stream().filter(p -> p.getUniqueId() != getUniqueId()).forEach(p -> {
|
|
if (p.getDatabasePlayer().isAllowed(Rank.Admin)) return;
|
|
p.sendPacket(new PacketPlayOutEntityDestroy(getEntityId()));
|
|
p.sendPacket(new PacketPlayOutNamedEntitySpawn(getHandle()));
|
|
if (p.canSee(this)) {
|
|
p.hidePlayer(this);
|
|
p.showPlayer(this);
|
|
}
|
|
});
|
|
|
|
//respawn
|
|
sendPacket(new PacketPlayOutRespawn(getWorld().getEnvironment().getId(), getHandle().getWorld().getDifficulty(), getHandle().getWorld().getWorldData().getType(), getHandle().playerInteractManager.getGameMode()));
|
|
getHandle().playerConnection.teleport(new Location(getWorld(), getHandle().locX, getHandle().locY, getHandle().locZ, getHandle().yaw, getHandle().pitch));
|
|
sendPacket(new PacketPlayOutSpawnPosition(getHandle().getWorld().getSpawn()));
|
|
sendPacket(new PacketPlayOutExperience(getHandle().exp, getHandle().expTotal, getHandle().expLevel));
|
|
getHandle().updateInventory(getHandle().defaultContainer);
|
|
updateScaledHealth();
|
|
sendPacket(new PacketPlayOutHeldItemSlot(getHandle().inventory.itemInHandIndex));
|
|
getHandle().updateAbilities();
|
|
for (MobEffect effect : getHandle().getEffects())
|
|
sendPacket(new PacketPlayOutEntityEffect(getHandle().getId(), effect));
|
|
|
|
if (this.gameProfile != profile) {
|
|
for (CustomPlayer player : Core.getOnlinePlayers()) {
|
|
if (player.getDatabasePlayer().isAllowed(Rank.Admin)) return;
|
|
player.initScoreboard();
|
|
player.getDatabasePlayer().getRankAsync().whenComplete((rank, throwable) -> getScoreboard().getTeam(rank.getTeam()).addEntry(player.getDisplayName()));
|
|
player.getScoreboard().getTeam(Rank.Premium.getTeam()).addEntry(getDisplayName());
|
|
}
|
|
} else {
|
|
for (CustomPlayer player : Core.getOnlinePlayers()) {
|
|
player.initScoreboard();
|
|
getDatabasePlayer().getRankAsync().whenComplete((rank, throwable) -> player.getScoreboard().getTeam(rank.getTeam()).addEntry(getDisplayName()));
|
|
player.getDatabasePlayer().getRankAsync().whenComplete((rank, throwable) -> getScoreboard().getTeam(rank.getTeam()).addEntry(player.getDisplayName()));
|
|
}
|
|
}
|
|
}
|
|
|
|
public void removeNickName() {
|
|
if (isNicked()) {
|
|
nickedPlayers.remove(getUniqueId());
|
|
setGameProfile(getName(), gameProfile);
|
|
}
|
|
}
|
|
|
|
public boolean isNicked() {
|
|
return nickedPlayers.containsKey(getUniqueId());
|
|
}
|
|
|
|
/*
|
|
Quest
|
|
*/
|
|
|
|
@Getter private Quest quest;
|
|
|
|
|
|
/*
|
|
Miscellaneous
|
|
*/
|
|
|
|
/**
|
|
* open or close chests for player
|
|
*
|
|
* @param loc location, block at location must be a type of chest
|
|
* @param open open or close the chest
|
|
*/
|
|
public void changeChestState(Location loc, boolean open) {
|
|
if (!(loc.getBlock() instanceof Chest) && !(loc.getBlock() instanceof ShulkerBox) && !(loc.getBlock() instanceof EnderChest) && !(loc.getBlock() instanceof DoubleChest))
|
|
return;
|
|
BlockPosition position = new BlockPosition(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
|
|
PacketPlayOutBlockAction blockActionPacket = new PacketPlayOutBlockAction(position, Block.getById(loc.getBlock().getTypeId()), 1, (open) ? 1 : 0);
|
|
sendPacket(blockActionPacket);
|
|
}
|
|
|
|
/**
|
|
* sets the amount of arrows that are in the body of the player
|
|
*
|
|
* @param count arrow count
|
|
*/
|
|
public void setArrowsInBody(int count) {
|
|
getHandle().getDataWatcher().set(new DataWatcherObject<>(10, DataWatcherRegistry.b), count);
|
|
}
|
|
|
|
public int getArrowsInBody() {
|
|
return getHandle().getDataWatcher().get(new DataWatcherObject<>(10, DataWatcherRegistry.b));
|
|
}
|
|
|
|
/**
|
|
* sends packets for item cooldown, items won't be disabled
|
|
*
|
|
* @param item item to have a cooldown
|
|
* @param time time in seconds
|
|
*/
|
|
public void setItemCooldown(ItemStack item, int time) {
|
|
sendPacket(new PacketPlayOutSetCooldown(CraftItemStack.asNMSCopy(item).getItem(), time));
|
|
}
|
|
|
|
public void hideToAll() {
|
|
for (CustomPlayer p : Core.getOnlinePlayers()) {
|
|
p.hidePlayer(this);
|
|
}
|
|
}
|
|
|
|
public void showToAll() {
|
|
for (CustomPlayer p : Core.getOnlinePlayers()) {
|
|
p.showPlayer(this);
|
|
}
|
|
}
|
|
|
|
public void strikeLightning(Location loc) {
|
|
net.minecraft.server.v1_12_R1.World nmsWorld = ((CraftWorld) loc.getWorld()).getHandle();
|
|
EntityLightning lightning = new EntityLightning(nmsWorld, loc.getX(), loc.getY(), loc.getZ(), true);
|
|
sendPacket(new PacketPlayOutSpawnEntityWeather(lightning));
|
|
playSound(loc, Sound.ENTITY_LIGHTNING_IMPACT, 20.0F, 1.0F);
|
|
playSound(loc, Sound.ENTITY_LIGHTNING_THUNDER, 20.0F, 1.0F);
|
|
}
|
|
|
|
public void setBlackScreen(int seconds) {
|
|
Blackscreen.setBlack(this, seconds);
|
|
}
|
|
|
|
public void setStoryResourcePack() {
|
|
setResourcePack("http://download1053.mediafireuserdownload.com/azvfl4fchheg/czy67lcvstrl9r5/TSF+Resource+Pack+v1.3.2.zip");
|
|
//setResourcePack("http://univento.eu/storyPack.zip");
|
|
}
|
|
|
|
public void initScoreboard() {
|
|
Scoreboard board = getScoreboard();
|
|
board.getTeams().forEach(Team::unregister);
|
|
|
|
for (Rank rank : Rank.values()) {
|
|
Team team = board.registerNewTeam(rank.getTeam());
|
|
team.setPrefix(rank.getTab());
|
|
team.setOption(Team.Option.NAME_TAG_VISIBILITY, Team.OptionStatus.ALWAYS);
|
|
}
|
|
}
|
|
|
|
public void setLabyModFeatures(HashMap<LabyMod, Boolean> list) {
|
|
HashMap<String, Boolean> temp = new HashMap<>();
|
|
for (LabyMod feature : list.keySet())
|
|
temp.put(feature.name(), list.get(feature));
|
|
|
|
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
|
|
try {
|
|
ObjectOutputStream out = new ObjectOutputStream(byteOut);
|
|
out.writeObject(temp);
|
|
ByteBuf byteBuf = Unpooled.copiedBuffer(byteOut.toByteArray());
|
|
PacketDataSerializer packetDataSerializer = new PacketDataSerializer(byteBuf);
|
|
PacketPlayOutCustomPayload packet = new PacketPlayOutCustomPayload("LABYMOD", packetDataSerializer);
|
|
sendPacket(packet);
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* crashes the players client
|
|
*/
|
|
public void crashClient() {
|
|
sendPacket(new PacketPlayOutExplosion(9999999999D,
|
|
9999999999D, 9999999999D, 9999999999F,
|
|
new ArrayList<>(), new Vec3D(9999999999D,
|
|
9999999999D, 9999999999D)));
|
|
}
|
|
|
|
/*
|
|
Packets
|
|
*/
|
|
|
|
public void sendPacket(Packet<?> packet) {
|
|
getHandle().playerConnection.sendPacket(packet);
|
|
}
|
|
|
|
private Field getField(Class<?> clazz, String name) {
|
|
try {
|
|
Field field = clazz.getDeclaredField(name);
|
|
field.setAccessible(true);
|
|
return field;
|
|
} catch (Exception ex) {
|
|
ex.printStackTrace();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/*
|
|
Other
|
|
*/
|
|
|
|
public CompletableFuture<Location> getLastLocation() {
|
|
CompletableFuture<Location> future = new CompletableFuture<>();
|
|
DATABASE_PLAYER.getObjectFromDatabase().whenComplete((entries, throwable) -> {
|
|
JsonObject json = entries.getJsonObject("Pos");
|
|
future.complete(new Location(Bukkit.getWorld("world"), json.getDouble("X"), json.getDouble("Y"), json.getDouble("Z"),
|
|
Float.parseFloat(json.getString("Yaw")), Float.parseFloat(json.getString("Pitch"))));
|
|
});
|
|
return future;
|
|
}
|
|
|
|
public void warn(WarnReason reason, CustomPlayer warner, String proof) {
|
|
DATABASE_PLAYER.warn(reason, warner.getUniqueId().toString(), proof);
|
|
}
|
|
|
|
public void clearPotionEffects() {
|
|
for(PotionEffect potion : getActivePotionEffects()) {
|
|
removePotionEffect(potion.getType());
|
|
}
|
|
}
|
|
|
|
} |