package com.laytonsmith.abstraction.bukkit.entities;
import com.laytonsmith.PureUtilities.ClassLoading.ClassDiscovery;
import com.laytonsmith.PureUtilities.Common.ReflectionUtils;
import com.laytonsmith.abstraction.MCCommandSender;
import com.laytonsmith.abstraction.MCEntity;
import com.laytonsmith.abstraction.MCItemStack;
import com.laytonsmith.abstraction.MCLocation;
import com.laytonsmith.abstraction.MCNote;
import com.laytonsmith.abstraction.MCOfflinePlayer;
import com.laytonsmith.abstraction.MCPlayer;
import com.laytonsmith.abstraction.MCPlayerInventory;
import com.laytonsmith.abstraction.MCScoreboard;
import com.laytonsmith.abstraction.StaticLayer;
import com.laytonsmith.abstraction.bukkit.BukkitConvertor;
import com.laytonsmith.abstraction.bukkit.BukkitMCItemStack;
import com.laytonsmith.abstraction.bukkit.BukkitMCLocation;
import com.laytonsmith.abstraction.bukkit.BukkitMCPlayerInventory;
import com.laytonsmith.abstraction.bukkit.BukkitMCScoreboard;
import com.laytonsmith.abstraction.enums.MCInstrument;
import com.laytonsmith.abstraction.enums.MCSound;
import com.laytonsmith.abstraction.enums.MCSoundCategory;
import com.laytonsmith.abstraction.enums.MCVersion;
import com.laytonsmith.abstraction.enums.MCWeather;
import com.laytonsmith.abstraction.enums.bukkit.BukkitMCInstrument;
import com.laytonsmith.abstraction.enums.bukkit.BukkitMCSound;
import com.laytonsmith.abstraction.enums.bukkit.BukkitMCSoundCategory;
import com.laytonsmith.abstraction.enums.bukkit.BukkitMCWeather;
import com.laytonsmith.commandhelper.CommandHelperPlugin;
import com.laytonsmith.core.Static;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Note;
import org.bukkit.Server;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import java.lang.reflect.InvocationTargetException;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
/**
*
*
*/
public class BukkitMCPlayer extends BukkitMCHumanEntity implements MCPlayer, MCCommandSender, MCOfflinePlayer {
Player p;
public BukkitMCPlayer(Entity player) {
super(player);
this.p = (Player) player;
}
public Player _Player() {
return p;
}
@Override
public boolean canSee(MCPlayer p) {
return this.p.canSee(((BukkitMCPlayer)p)._Player());
}
@Override
public void chat(String chat) {
p.chat(chat);
}
@Override
public InetSocketAddress getAddress() {
return p.getAddress();
}
@Override
public boolean getAllowFlight() {
return p.getAllowFlight();
}
@Override
public MCLocation getCompassTarget() {
return new BukkitMCLocation(p.getCompassTarget());
}
@Override
public String getDisplayName() {
return p.getDisplayName();
}
@Override
public float getExp() {
return p.getExp();
}
@Override
public long getFirstPlayed() {
return p.getFirstPlayed();
}
@Override
public MCPlayerInventory getInventory() {
if (p == null || p.getInventory() == null) {
return null;
}
return new BukkitMCPlayerInventory(p.getInventory());
}
@Override
public MCItemStack getItemAt(Integer slot) {
if (slot == null) {
return new BukkitMCItemStack(p.getItemInHand());
}
ItemStack is = null;
//Special slots
if (slot == 100) {
is = p.getInventory().getBoots();
} else if (slot == 101) {
is = p.getInventory().getLeggings();
} else if (slot == 102) {
is = p.getInventory().getChestplate();
} else if (slot == 103) {
is = p.getInventory().getHelmet();
} else if (slot == -106) {
is = p.getInventory().getItemInOffHand();
}
if (slot >= 0 && slot <= 35) {
is = p.getInventory().getItem(slot);
}
if (is == null) {
return null;
} else {
return new BukkitMCItemStack(is);
}
}
@Override
public long getLastPlayed() {
return p.getLastPlayed();
}
@Override
public int getLevel() {
return p.getLevel();
}
@Override
public MCPlayer getPlayer() {
return new BukkitMCPlayer(p);
}
@Override
public long getPlayerTime() {
return p.getPlayerTime();
}
@Override
public MCWeather getPlayerWeather() {
return BukkitMCWeather.getConvertor().getAbstractedEnum(p.getPlayerWeather());
}
@Override
public int getRemainingFireTicks() {
return p.getFireTicks();
}
@Override
public int getTotalExperience()
{
return p.getTotalExperience();
}
@Override
public int getExpToLevel() {
return p.getExpToLevel();
}
@Override
public int getExpAtLevel() {
int level = p.getLevel();
if(Static.getServer().getMinecraftVersion().lt(MCVersion.MC1_8)) {
if (level > 30) {
return (int) (3.5 * Math.pow(level, 2) - 151.5 * level + 2220);
}
if(level > 15) {
return (int) (1.5 * Math.pow(level, 2) - 29.5 * level + 360);
}
return 17 * level;
} else {
if (level > 30) {
return (int) (4.5 * Math.pow(level, 2) - 162.5 * level + 2220);
}
if (level > 15) {
return (int) (2.5 * Math.pow(level, 2) - 40.5 * level + 360);
}
return (int) (Math.pow(level, 2) + 6 * level);
}
}
@Override
public void setFlySpeed(float speed) {
p.setFlySpeed(speed);
}
@Override
public float getFlySpeed() {
return p.getFlySpeed();
}
@Override
public void setWalkSpeed(float speed) {
p.setWalkSpeed(speed);
}
@Override
public float getWalkSpeed() {
return p.getWalkSpeed();
}
@Override
public void giveExp(int xp) {
p.giveExp(xp);
}
@Override
public boolean hasPlayedBefore() {
return p.hasPlayedBefore();
}
@Override
public boolean isBanned() {
return p.isBanned();
}
@Override
public boolean isOnline() {
return p.isOnline();
}
@Override
public boolean isOp() {
return p.isOp();
}
@Override
public boolean hasPermission(String perm) {
return p.hasPermission(perm);
}
@Override
public boolean isPermissionSet(String perm) {
return p.isPermissionSet(perm);
}
@Override
public List<String> getGroups() {
// As in https://github.com/sk89q/WorldEdit/blob/master/
// worldedit-bukkit/src/main/java/com/sk89q/wepif/DinnerPermsResolver.java#L112-L126
List<String> groupNames = new ArrayList<String>();
for (PermissionAttachmentInfo permAttach : p.getEffectivePermissions()) {
String perm = permAttach.getPermission();
if (!(perm.startsWith(Static.groupPrefix) && permAttach.getValue())) {
continue;
}
groupNames.add(perm.substring(Static.groupPrefix.length(), perm.length()));
}
return groupNames;
}
@Override
public boolean inGroup(String groupName) {
return getGroups().contains(groupName);
}
@Override
public void setOp(boolean bln) {
p.setOp(bln);
}
@Override
public boolean isSneaking() {
return p.isSneaking();
}
@Override
public boolean isSprinting() {
return p.isSprinting();
}
@Override
public boolean isWhitelisted() {
return p.isWhitelisted();
}
@Override
public void kickPlayer(String message) {
p.kickPlayer(message);
}
@Override
public boolean removeEffect(int potionID) {
PotionEffectType t = PotionEffectType.getById(potionID);
boolean hasIt = false;
for(PotionEffect pe : p.getActivePotionEffects()) {
if (pe.getType() == t) {
hasIt = true;
break;
}
}
p.removePotionEffect(t);
return hasIt;
}
@Override
public void resetPlayerTime() {
p.resetPlayerTime();
}
@Override
public void resetPlayerWeather() {
p.resetPlayerWeather();
}
@Override
public void sendMessage(String string) {
//The client doesn't like tabs
string = string.replaceAll("\t", " ");
p.sendMessage(string);
}
@Override
public void sendTexturePack(String url) {
p.setTexturePack(url);
}
@Override
public void sendResourcePack(String url) {
p.setResourcePack(url);
}
@Override
public void setAllowFlight(boolean flight) {
p.setAllowFlight(flight);
}
@Override
public void setBanned(boolean banned) {
p.setBanned(banned);
}
@Override
public void setCompassTarget(MCLocation l) {
p.setCompassTarget(((BukkitMCLocation) l)._Location());
}
@Override
public void setDisplayName(String name) {
p.setDisplayName(name);
}
@Override
public void setExp(float i) {
p.setExp(i);
}
@Override
public void setFlying(boolean flight) {
p.setFlying(flight);
}
/*public void setHealth(int i) {
if(i == 0){
this.fireEntityDamageEvent(MCDamageCause.CUSTOM);
}
p.setHealth(i);
}*/
@Override
public void setLevel(int xp) {
p.setLevel(xp);
}
@Override
public void setPlayerTime(Long time, boolean relative) {
p.setPlayerTime(time, relative);
}
@Override
public void setPlayerWeather(MCWeather type) {
p.setPlayerWeather(BukkitMCWeather.getConvertor().getConcreteEnum(type));
}
@Override
public void setRemainingFireTicks(int i) {
p.setFireTicks(i);
}
@Override
public void setSpectatorTarget(MCEntity entity) {
try {
if(entity == null){
p.setSpectatorTarget(null);
return;
}
p.setSpectatorTarget((Entity) entity.getHandle());
} catch(NoSuchMethodError ex){
// Probably 1.8.6 or prior
}
}
@Override
public MCEntity getSpectatorTarget() {
try {
return BukkitConvertor.BukkitGetCorrectEntity(p.getSpectatorTarget());
} catch(NoSuchMethodError ex){
// Probably 1.8.6 or prior
return null;
}
}
@Override
public void setTempOp(Boolean value) throws ClassNotFoundException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Server server = Bukkit.getServer();
Class serverClass = ClassDiscovery.getDefaultInstance().forFuzzyName("org.bukkit.craftbukkit.*", "CraftServer").loadClass();
if (!server.getClass().isAssignableFrom(serverClass)) {
throw new IllegalStateException("Running server isn't CraftBukkit");
}
try {
//Probably 1.4.6
Class nmsMinecraftServerClass = ClassDiscovery.getDefaultInstance().forFuzzyName("net.minecraft.server.*", "MinecraftServer").loadClass();
/*n.m.s.MinecraftServer*/ Object nmsServer = ReflectionUtils.invokeMethod(nmsMinecraftServerClass, null, "getServer");
/*n.m.s.PlayerList*/ Object nmsPlayerList = ReflectionUtils.invokeMethod(nmsServer, "getPlayerList");
Set opSet = (Set)ReflectionUtils.get(ClassDiscovery.getDefaultInstance().forFuzzyName("net.minecraft.server.*", "PlayerList").loadClass(), nmsPlayerList, "operators");
// since all Java objects pass by reference, we don't need to set field back to object
if (value) {
opSet.add(p.getName().toLowerCase());
} else {
opSet.remove(p.getName().toLowerCase());
}
} catch(ClassCastException ex){
// Probably 1.7.8
Class nmsMinecraftServerClass = ClassDiscovery.getDefaultInstance().forFuzzyName("net.minecraft.server.*", "MinecraftServer").loadClass();
/*n.m.s.MinecraftServer*/ Object nmsServer = ReflectionUtils.invokeMethod(nmsMinecraftServerClass, null, "getServer");
/*n.m.s.PlayerList*/ Object nmsPlayerList = ReflectionUtils.invokeMethod(nmsServer, "getPlayerList");
/*n.m.s.OpList*/ Object opSet = ReflectionUtils.get(ClassDiscovery.getDefaultInstance().forFuzzyName("net.minecraft.server.*", "PlayerList").loadClass(), nmsPlayerList, "operators");
//opSet.getClass().getSuperclass() == n.m.s.JsonList
Map/*<String, n.m.s.OpListEntry>*/ d = (Map)ReflectionUtils.get(opSet.getClass().getSuperclass(), opSet, "d");
if(value){
/*n.m.s.OpListEntry*/ Class nmsOpListEntry = ClassDiscovery.getDefaultInstance().forFuzzyName("net.minecraft.server.*", "OpListEntry").loadClass();
Class nmsGameProfile;
try {
/*net.minecraft.util.com.mojang.authlib.GameProfile*/ nmsGameProfile = Class.forName("net.minecraft.util.com.mojang.authlib.GameProfile");
} catch (ClassNotFoundException eee){
// Probably 1.8
/*com.mojang.authlib.GameProfile*/ nmsGameProfile = Class.forName("com.mojang.authlib.GameProfile");
}
Object gameProfile = ReflectionUtils.invokeMethod(p, "getProfile");
Object opListEntry;
try {
opListEntry = ReflectionUtils.newInstance(nmsOpListEntry, new Class[]{nmsGameProfile, int.class}, new Object[]{gameProfile, 4});
} catch (ReflectionUtils.ReflectionException e) {
// Probably 1.8.6
opListEntry = ReflectionUtils.newInstance(nmsOpListEntry, new Class[]{nmsGameProfile, int.class, boolean.class}, new Object[]{gameProfile, 4, false});
}
d.put(p.getUniqueId().toString(), opListEntry);
} else {
d.remove(p.getUniqueId().toString());
}
}
p.recalculatePermissions();
}
@Override
public void setTotalExperience(int total)
{
p.setTotalExperience(total);
}
@Override
public void setVanished(boolean set, MCPlayer to) {
if (!set) {
p.showPlayer(((BukkitMCPlayer)to)._Player());
} else {
p.hidePlayer(((BukkitMCPlayer)to)._Player());
}
}
@Override
public void setWhitelisted(boolean value) {
p.setWhitelisted(value);
}
@Override
public void setPlayerListName(String listName) {
p.setPlayerListName(listName);
}
@Override
public String getPlayerListName() {
return p.getPlayerListName();
}
@Override
public boolean isNewPlayer() {
//Note the reversed logic here. If they have NOT played before, they are
//a new player.
return !p.getServer().getOfflinePlayer(p.getName()).hasPlayedBefore();
}
@Override
public String getHost() {
return Static.GetHost(this);
}
@Override
public void sendBlockChange(MCLocation loc, int material, byte data) {
p.sendBlockChange(((Location) loc.getHandle()), material, data);
}
@Override
public void sendSignTextChange(MCLocation loc, String[] lines) {
p.sendSignChange(((Location) loc.getHandle()), lines);
}
@Override
public void playNote(MCLocation loc, MCInstrument instrument, MCNote note) {
p.playNote((Location) loc.getHandle(), BukkitMCInstrument.getConvertor().getConcreteEnum(instrument), (Note) note.getHandle());
}
@Override
public void playSound(MCLocation l, MCSound sound, float volume, float pitch) {
p.playSound(((BukkitMCLocation) l).asLocation(),
((BukkitMCSound) sound).getConcrete(), volume, pitch);
}
@Override
public void playSound(MCLocation l, String sound, float volume, float pitch) {
p.playSound(((BukkitMCLocation) l).asLocation(), sound, volume, pitch);
}
@Override
public void playSound(MCLocation l, MCSound sound, MCSoundCategory category, float volume, float pitch) {
try {
p.playSound((Location) l.getHandle(), ((BukkitMCSound) sound).getConcrete(),
BukkitMCSoundCategory.getConvertor().getConcreteEnum(category), volume, pitch);
} catch(NoClassDefFoundError ex) {
// probably prior to 1.11, ignore category
playSound(l, sound, volume, pitch);
}
}
@Override
public void playSound(MCLocation l, String sound, MCSoundCategory category, float volume, float pitch) {
try {
p.playSound((Location) l.getHandle(), sound,
BukkitMCSoundCategory.getConvertor().getConcreteEnum(category), volume, pitch);
} catch(NoClassDefFoundError ex) {
// probably prior to 1.11, ignore category
playSound(l, sound, volume, pitch);
}
}
@Override
public void stopSound(MCSound sound) {
try {
p.stopSound(((BukkitMCSound) sound).getConcrete());
} catch(NoSuchMethodError ex){
// probably prior to 1.10
}
}
@Override
public void stopSound(String sound) {
try {
p.stopSound(sound);
} catch(NoSuchMethodError ex){
// probably prior to 1.10
}
}
@Override
public void stopSound(MCSound sound, MCSoundCategory category) {
try {
p.stopSound(((BukkitMCSound) sound).getConcrete(),
BukkitMCSoundCategory.getConvertor().getConcreteEnum(category));
} catch(NoClassDefFoundError ex){
// probably prior to 1.11, ignore category
stopSound(sound);
}
}
@Override
public void stopSound(String sound, MCSoundCategory category) {
try {
p.stopSound(sound, BukkitMCSoundCategory.getConvertor().getConcreteEnum(category));
} catch(NoClassDefFoundError ex){
// probably prior to 1.11, ignore category
stopSound(sound);
}
}
@Override
public int getFoodLevel() {
return p.getFoodLevel();
}
@Override
public void setFoodLevel(int f) {
p.setFoodLevel(f);
}
@Override
public float getSaturation() {
return p.getSaturation();
}
@Override
public void setSaturation(float s) {
p.setSaturation(s);
}
@Override
public float getExhaustion() {
return p.getExhaustion();
}
@Override
public void setExhaustion(float e) {
p.setExhaustion(e);
}
@Override
public MCLocation getBedSpawnLocation() {
Location loc = p.getBedSpawnLocation();
return loc == null ? null : new BukkitMCLocation(loc);
}
@Override
public UUID getUniqueID() {
return p.getUniqueId();
}
@Override
public void setBedSpawnLocation(MCLocation l, boolean forced) {
p.setBedSpawnLocation((Location) l.getHandle(), forced);
}
@Override
public MCEntity getVehicle() {
return new BukkitMCEntity(p.getVehicle());
}
@Override
public void sendPluginMessage(String channel, byte[] message) {
StaticLayer.GetConvertor().GetPluginMeta().openOutgoingChannel(channel);
p.sendPluginMessage(CommandHelperPlugin.self, channel, message);
}
@Override
public boolean isFlying() {
return p.isFlying();
}
@Override
public void updateInventory() {
p.updateInventory();
}
@Override
public MCScoreboard getScoreboard() {
return new BukkitMCScoreboard(p.getScoreboard());
}
@Override
public void setScoreboard(MCScoreboard board) {
p.setScoreboard(((BukkitMCScoreboard) board)._scoreboard());
}
}