blue.lapis.pore.impl.entity.PorePlayer.java Source code

Java tutorial

Introduction

Here is the source code for blue.lapis.pore.impl.entity.PorePlayer.java

Source

/*
 * Pore
 * Copyright (c) 2014-2015, Lapis <https://github.com/LapisBlue>
 *
 * The MIT License
 *
 * 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.
 */
package blue.lapis.pore.impl.entity;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static org.spongepowered.api.data.manipulator.catalog.CatalogEntityData.EXPERIENCE_HOLDER_DATA;
import static org.spongepowered.api.data.manipulator.catalog.CatalogEntityData.FLYING_DATA;
import static org.spongepowered.api.data.manipulator.catalog.CatalogEntityData.FOOD_DATA;
import static org.spongepowered.api.data.manipulator.catalog.CatalogEntityData.GAME_MODE_DATA;
import static org.spongepowered.api.data.manipulator.catalog.CatalogEntityData.INVISIBILITY_DATA;
import static org.spongepowered.api.data.manipulator.catalog.CatalogEntityData.JOIN_DATA;
import static org.spongepowered.api.data.manipulator.catalog.CatalogEntityData.RESPAWN_LOCATION_DATA;
import static org.spongepowered.api.data.manipulator.catalog.CatalogEntityData.SNEAKING_DATA;
import static org.spongepowered.api.data.manipulator.catalog.CatalogEntityData.WHITELIST_DATA;

import blue.lapis.pore.Pore;
import blue.lapis.pore.converter.type.entity.EntityConverter;
import blue.lapis.pore.converter.type.entity.player.GameModeConverter;
import blue.lapis.pore.converter.type.material.MaterialConverter;
import blue.lapis.pore.converter.type.statistic.AchievementConverter;
import blue.lapis.pore.converter.type.statistic.StatisticConverter;
import blue.lapis.pore.converter.type.world.effect.SoundConverter;
import blue.lapis.pore.converter.vector.LocationConverter;
import blue.lapis.pore.converter.vector.VectorConverter;
import blue.lapis.pore.converter.wrapper.WrapperConverter;
import blue.lapis.pore.impl.scoreboard.PoreScoreboard;

import com.flowpowered.math.vector.Vector3d;
import com.google.common.base.Optional;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.NotImplementedException;
import org.bukkit.Achievement;
import org.bukkit.Effect;
import org.bukkit.GameMode;
import org.bukkit.Instrument;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Note;
import org.bukkit.Sound;
import org.bukkit.Statistic;
import org.bukkit.WeatherType;
import org.bukkit.conversations.Conversation;
import org.bukkit.conversations.ConversationAbandonedEvent;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.map.MapView;
import org.bukkit.plugin.Plugin;
import org.bukkit.scoreboard.Scoreboard;
import org.spongepowered.api.block.BlockTypes;
import org.spongepowered.api.effect.sound.SoundType;
import org.spongepowered.api.entity.player.Player;
import org.spongepowered.api.entity.player.tab.PlayerTabInfo;
import org.spongepowered.api.resourcepack.ResourcePacks;
import org.spongepowered.api.statistic.BlockStatistic;
import org.spongepowered.api.statistic.EntityStatistic;
import org.spongepowered.api.statistic.StatisticGroup;
import org.spongepowered.api.text.Text;
import org.spongepowered.api.text.Texts;
import org.spongepowered.api.text.title.Titles;
import org.spongepowered.api.util.TextMessageException;

import java.io.FileNotFoundException;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

public class PorePlayer extends PoreHumanEntity implements org.bukkit.entity.Player {

    public static PorePlayer of(Player handle) {
        return WrapperConverter.of(PorePlayer.class, handle);
    }

    protected PorePlayer(Player handle) {
        super(handle);
    }

    @Override
    public Player getHandle() {
        return (Player) super.getHandle();
    }

    @Override
    public EntityType getType() {
        return EntityType.PLAYER;
    }

    @Override
    public String getDisplayName() {
        return super.getCustomName();
    }

    @Override
    public void setDisplayName(String name) {
        super.setCustomName(name);
    }

    @Override
    @SuppressWarnings("deprecation")
    public String getPlayerListName() {
        Optional<PlayerTabInfo> info = this.getHandle().getTabList().getPlayer(this.getUniqueId());
        return info.isPresent() ? Texts.legacy().to(info.get().getDisplayName()) : this.getDisplayName();
    }

    @Override
    @SuppressWarnings("deprecation")
    public void setPlayerListName(String name) {
        Optional<PlayerTabInfo> info = this.getHandle().getTabList().getPlayer(this.getUniqueId());
        if (info.isPresent()) {
            try {
                info.get().setDisplayName(Texts.legacy().from(name));
            } catch (TextMessageException ex) {
                throw new IllegalArgumentException(ex);
            }
        }
    }

    @Override
    public Location getCompassTarget() {
        throw new NotImplementedException("TODO");
    }

    @Override
    public void setCompassTarget(Location loc) {
        throw new NotImplementedException("TODO");
    }

    @Override
    public InetSocketAddress getAddress() {
        return getHandle().getConnection().getAddress();
    }

    @Override
    public boolean isConversing() {
        throw new NotImplementedException("TODO");
    }

    @Override
    public void acceptConversationInput(String input) {
        throw new NotImplementedException("TODO");
    }

    @Override
    public boolean beginConversation(Conversation conversation) {
        throw new NotImplementedException("TODO");
    }

    @Override
    public void abandonConversation(Conversation conversation) {
        throw new NotImplementedException("TODO");
    }

    @Override
    public void abandonConversation(Conversation conversation, ConversationAbandonedEvent details) {
        throw new NotImplementedException("TODO");
    }

    @Override
    public void sendRawMessage(String message) {
        this.sendMessage(message);
    }

    @Override
    public void kickPlayer(String message) {
        throw new NotImplementedException("TODO");
    }

    @Override
    public void chat(String msg) {
        throw new NotImplementedException("TODO");
    }

    @Override
    public boolean performCommand(String command) {
        throw new NotImplementedException("TODO");
    }

    @Override
    public boolean isSneaking() {
        return hasData(SNEAKING_DATA);
    }

    @Override
    public void setSneaking(boolean sneak) {
        if (sneak != isSneaking()) {
            if (sneak) {
                getHandle().offer(getHandle().getOrCreate(SNEAKING_DATA).get().sneaking().set(true));
            } else {
                getHandle().remove(SNEAKING_DATA);
            }
        }
    }

    @Override
    public boolean isSprinting() {
        throw new NotImplementedException("TODO");
    }

    @Override
    public void setSprinting(boolean sprinting) {
        throw new NotImplementedException("TODO");
    }

    @Override
    public void saveData() {
        throw new NotImplementedException("TODO");
    }

    @Override
    public void loadData() {
        throw new NotImplementedException("TODO");
    }

    @Override
    public boolean isSleepingIgnored() {
        //TODO: This feature is deeply implemented in CB, so I have no damn clue how we're going to manage to implement
        // this on top of Sponge short of mixins (which is obviously a really bad idea).
        throw new NotImplementedException("TODO");
    }

    @Override
    public void setSleepingIgnored(boolean isSleeping) {
        //TODO: Same deal here. I commented the NotImplementedExcpetion out temporarily to keep Essentials from
        // freaking out every two seconds when it tries to call this method from a scheduler.
        //throw new NotImplementedException("TODO");
    }

    @Override
    public void playNote(Location loc, byte instrument, byte note) {
        throw new NotImplementedException("TODO");
    }

    @Override
    public void playNote(Location loc, Instrument instrument, Note note) {
        throw new NotImplementedException("TODO");
    }

    @Override
    public void playSound(Location location, Sound sound, float volume, float pitch) {
        getHandle().playSound(SoundConverter.of(sound), VectorConverter.create3d(location), volume, pitch);
    }

    @Override
    public void playSound(Location location, String sound, float volume, float pitch) {
        // TODO: Isn't the String sound the ID and not the name?
        //TODO: no idea whether this is right
        Optional<SoundType> spongeSound = Pore.getGame().getRegistry().getType(SoundType.class, sound);
        if (spongeSound.isPresent()) {
            getHandle().playSound(spongeSound.get(), VectorConverter.create3d(location), volume, pitch);
        }
    }

    @Override
    public void playEffect(Location loc, Effect effect, int data) {
        throw new NotImplementedException("TODO");
    }

    @Override
    public <T> void playEffect(Location loc, Effect effect, T data) {
        throw new NotImplementedException("TODO");
    }

    @Override
    public void sendBlockChange(Location loc, Material material, byte data) {
        throw new NotImplementedException("TODO");
    }

    @Override
    public boolean sendChunkChange(Location loc, int sx, int sy, int sz, byte[] data) {
        throw new NotImplementedException("TODO");
    }

    @Override
    public void sendBlockChange(Location loc, int material, byte data) {
        throw new NotImplementedException("TODO");
    }

    @Override
    public void sendSignChange(Location loc, String[] lines) throws IllegalArgumentException {
        throw new NotImplementedException("TODO");
    }

    @Override
    public void sendMap(MapView map) {
        throw new NotImplementedException("TODO");
    }

    @Override
    public void updateInventory() {
        throw new NotImplementedException("TODO");
    }

    @Override
    public void awardAchievement(Achievement achievement) {
        getHandle()
                .offer(getHandle().getAchievementData().achievements().add(AchievementConverter.of(achievement)));
    }

    @Override
    public void removeAchievement(Achievement achievement) {
        getHandle().offer(
                getHandle().getAchievementData().achievements().remove(AchievementConverter.of(achievement)));
    }

    @Override
    public boolean hasAchievement(Achievement achievement) {
        return getHandle().getAchievementData().achievements().contains(AchievementConverter.of(achievement));
    }

    @Override
    public void incrementStatistic(Statistic statistic) throws IllegalArgumentException {
        incrementStatistic(statistic, 1);
    }

    @Override
    public void decrementStatistic(Statistic statistic) throws IllegalArgumentException {
        decrementStatistic(statistic, 1);
    }

    @Override
    public void incrementStatistic(Statistic statistic, int amount) throws IllegalArgumentException {
        setStatistic(statistic, getStatistic(statistic) + amount);
    }

    @Override
    public void decrementStatistic(Statistic statistic, int amount) throws IllegalArgumentException {
        incrementStatistic(statistic, -amount);
    }

    private void setStatistic(org.spongepowered.api.statistic.Statistic statistic, int newValue) {
        getHandle().offer(getHandle().getStatisticData().statistics().put(statistic, (long) newValue));
    }

    @Override
    public void setStatistic(Statistic statistic, int newValue) throws IllegalArgumentException {
        checkNotNull(statistic, "Statistic must not be null");
        setStatistic(StatisticConverter.asStdStat(statistic), newValue);
    }

    private int getStatistic(org.spongepowered.api.statistic.Statistic statistic) {
        Long l = getHandle().getStatisticData().statistics().get().get(statistic);
        return l != null ? l.intValue() : 0;
    }

    @Override
    public int getStatistic(Statistic statistic) throws IllegalArgumentException {
        checkNotNull(statistic, "Statistic must not be null");
        checkArgument(statistic.getType() == Statistic.Type.UNTYPED,
                "Statistic " + statistic.toString() + " requires an additional parameter");
        return getStatistic(StatisticConverter.asStdStat(statistic));
    }

    @Override
    public void incrementStatistic(Statistic statistic, Material material) throws IllegalArgumentException {
        incrementStatistic(statistic, material, 1);
    }

    @Override
    public void decrementStatistic(Statistic statistic, Material material) throws IllegalArgumentException {
        decrementStatistic(statistic, material, 1);
    }

    @Override
    public int getStatistic(Statistic statistic, Material material) throws IllegalArgumentException {
        checkNotNull(statistic, "Statistic must not be null");
        checkArgument(statistic.getType() == Statistic.Type.BLOCK || statistic.getType() == Statistic.Type.ITEM,
                "Statistic " + statistic.name() + " cannot accept a Material parameter");
        StatisticGroup group = StatisticConverter.asGroupStat(statistic);
        Optional<BlockStatistic> stat = Pore.getGame().getRegistry().getBlockStatistic(group,
                MaterialConverter.asBlock(material));
        if (!stat.isPresent()) {
            throw new UnsupportedOperationException(
                    "Cannot get block statistic " + statistic.name() + " for material " + material.name());
        }
        return getStatistic(stat.get());
    }

    @Override
    public void setStatistic(Statistic statistic, Material material, int newValue) throws IllegalArgumentException {
        checkNotNull(statistic, "Statistic must not be null");
        checkState(statistic.getType() == Statistic.Type.BLOCK,
                "Statistic " + statistic.name() + " cannot accept a Material parameter");
        StatisticGroup group = StatisticConverter.asGroupStat(statistic);
        Optional<BlockStatistic> stat = Pore.getGame().getRegistry().getBlockStatistic(group,
                MaterialConverter.asBlock(material));
        if (!stat.isPresent()) {
            throw new UnsupportedOperationException(
                    "Cannot get block statistic " + statistic.name() + " for material " + material.name());
        }
        setStatistic(stat.get(), newValue);
    }

    @Override
    public void incrementStatistic(Statistic statistic, Material material, int amount)
            throws IllegalArgumentException {
        setStatistic(statistic, material, getStatistic(statistic, material) + amount);
    }

    @Override
    public void decrementStatistic(Statistic statistic, Material material, int amount)
            throws IllegalArgumentException {
        incrementStatistic(statistic, material, -amount);
    }

    @Override
    public void incrementStatistic(Statistic statistic, EntityType entityType) throws IllegalArgumentException {
        incrementStatistic(statistic, entityType, 1);
    }

    @Override
    public void decrementStatistic(Statistic statistic, EntityType entityType) throws IllegalArgumentException {
        decrementStatistic(statistic, entityType, 1);
    }

    @Override
    public int getStatistic(Statistic statistic, EntityType entityType) throws IllegalArgumentException {
        checkNotNull(statistic, "Statistic must not be null");
        checkState(statistic.getType() == Statistic.Type.ENTITY,
                "Statistic " + statistic.name() + " cannot accept an Entity parameter");
        StatisticGroup group = StatisticConverter.asGroupStat(statistic);
        Optional<EntityStatistic> stat = Pore.getGame().getRegistry().getEntityStatistic(group,
                EntityConverter.of(entityType));
        if (!stat.isPresent()) {
            throw new UnsupportedOperationException(
                    "Cannot get entity statistic " + statistic.name() + " for entity " + entityType.name());
        }
        return getStatistic(stat.get());
    }

    @Override
    public void incrementStatistic(Statistic statistic, EntityType entityType, int amount)
            throws IllegalArgumentException {
        setStatistic(statistic, entityType, getStatistic(statistic, entityType) + amount);
    }

    @Override
    public void decrementStatistic(Statistic statistic, EntityType entityType, int amount) {
        incrementStatistic(statistic, entityType, -amount);
    }

    @Override
    public void setStatistic(Statistic statistic, EntityType entityType, int newValue) {
        checkNotNull(statistic, "Statistic must not be null");
        checkState(statistic.getType() == Statistic.Type.ENTITY,
                "Statistic " + statistic.name() + " cannot accept an entity parameter");
        StatisticGroup group = StatisticConverter.asGroupStat(statistic);
        Optional<EntityStatistic> stat = Pore.getGame().getRegistry().getEntityStatistic(group,
                EntityConverter.of(entityType));
        if (!stat.isPresent()) {
            throw new UnsupportedOperationException(
                    "Cannot get entity statistic " + statistic.name() + " for entity " + entityType.name());
        }
        setStatistic(stat.get(), newValue);
    }

    @Override
    public void setPlayerTime(long time, boolean relative) {
        throw new NotImplementedException("TODO");
    }

    @Override
    public long getPlayerTime() {
        throw new NotImplementedException("TODO");
    }

    @Override
    public long getPlayerTimeOffset() {
        throw new NotImplementedException("TODO");
    }

    @Override
    public boolean isPlayerTimeRelative() {
        throw new NotImplementedException("TODO");
    }

    @Override
    public void resetPlayerTime() {
        throw new NotImplementedException("TODO");
    }

    @Override
    public void setPlayerWeather(WeatherType type) {
        throw new NotImplementedException("TODO");
    }

    @Override
    public WeatherType getPlayerWeather() {
        throw new NotImplementedException("TODO");
    }

    @Override
    public void resetPlayerWeather() {
        throw new NotImplementedException("TODO");
    }

    @Override
    public void giveExp(int amount) {
        setTotalExperience(getTotalExperience() + amount);
    }

    @Override
    public void giveExpLevels(int amount) {
        setLevel(getLevel() + amount);
    }

    @Override
    public float getExp() {
        if (!hasData(EXPERIENCE_HOLDER_DATA)) {
            return 0;
        }
        return getHandle().get(EXPERIENCE_HOLDER_DATA).get().experienceSinceLevel().get()
                / getHandle().get(EXPERIENCE_HOLDER_DATA).get().getExperienceBetweenLevels().get();
    }

    @Override
    public void setExp(float exp) {
        int newExp = (int) (getHandle().getOrCreate(EXPERIENCE_HOLDER_DATA).get().getExperienceBetweenLevels().get()
                * exp);
        //TODO: setExperienceSinceLevel(newExp)
        getHandle().get(EXPERIENCE_HOLDER_DATA).get().totalExperience();
        throw new NotImplementedException("TODO");
    }

    @Override
    public int getLevel() {
        return hasData(EXPERIENCE_HOLDER_DATA) ? getHandle().get(EXPERIENCE_HOLDER_DATA).get().level().get() : 0;
    }

    @Override
    public void setLevel(int level) {
        throw new NotImplementedException("TODO");
    }

    @Override
    public int getTotalExperience() {
        return hasData(EXPERIENCE_HOLDER_DATA)
                ? getHandle().get(EXPERIENCE_HOLDER_DATA).get().totalExperience().get()
                : 0;
    }

    @Override
    public void setTotalExperience(int exp) {
        throw new NotImplementedException("TODO");
    }

    @Override
    public float getExhaustion() {
        return getHandle().get(FOOD_DATA).get().exhaustion().get().floatValue();
    }

    @Override
    public void setExhaustion(float value) {
        getHandle().get(FOOD_DATA).get().exhaustion().set((double) value);
    }

    @Override
    public float getSaturation() {
        return getHandle().get(FOOD_DATA).get().saturation().get().floatValue();
    }

    @Override
    public void setSaturation(float value) {
        getHandle().get(FOOD_DATA).get().saturation().set((double) value);
    }

    @Override
    public int getFoodLevel() {
        return getHandle().get(FOOD_DATA).get().foodLevel().get();
    }

    @Override
    public void setFoodLevel(int value) {
        getHandle().get(FOOD_DATA).get().foodLevel().set(value);
    }

    @Override
    public boolean isOnline() {
        return getHandle().isOnline();
    }

    @Override
    public boolean isBanned() {
        throw new NotImplementedException("TODO"); //TODO: Use the BanService
    }

    @Override
    public void setBanned(boolean banned) {
        throw new NotImplementedException("TODO"); //TODO: Use the BanService
    }

    @Override
    public boolean isWhitelisted() {
        return hasData(WHITELIST_DATA) && getHandle().get(WHITELIST_DATA).get().whitelisted().get();
    }

    @Override
    public void setWhitelisted(boolean value) {
        if (value != isWhitelisted()) {
            if (value) {
                getHandle().offer(getHandle().getOrCreate(WHITELIST_DATA).get().whitelisted().set(true));
            } else {
                getHandle().remove(WHITELIST_DATA);
            }
        }
    }

    @Override
    public org.bukkit.entity.Player getPlayer() {
        return this;
    }

    @Override
    public long getFirstPlayed() {
        return getHandle().get(JOIN_DATA).get().firstPlayed().get().getTime();
    }

    @Override
    public long getLastPlayed() {
        return getHandle().get(JOIN_DATA).get().lastPlayed().get().getTime();
    }

    @Override
    public boolean hasPlayedBefore() {
        throw new NotImplementedException("TODO");
    }

    @Override
    public Location getBedSpawnLocation() {
        return hasData(RESPAWN_LOCATION_DATA)
                ? LocationConverter
                        .fromVector3d(getHandle().getWorld(),
                                getHandle().get(RESPAWN_LOCATION_DATA).get().respawnLocation().get()
                                        .get(getWorld().getUID()))
                : null;
    }

    @Override
    public void setBedSpawnLocation(Location location) {
        setBedSpawnLocation(location, false);
    }

    @Override
    public void setBedSpawnLocation(Location location, boolean force) {
        org.spongepowered.api.world.Location spongeLoc = LocationConverter.of(location);
        //noinspection ConstantConditions
        if (force || spongeLoc.getBlockType() == BlockTypes.BED) {
            getHandle().offer(getHandle().get(RESPAWN_LOCATION_DATA).get().respawnLocation().put(
                    location.getWorld().getUID(), new Vector3d(location.getX(), location.getY(), location.getZ())));
        }
    }

    @Override
    public void hidePlayer(org.bukkit.entity.Player player) {
        PorePlayer porePlayer = (PorePlayer) player;
        porePlayer.getHandle().offer(porePlayer.getHandle().getOrCreate(INVISIBILITY_DATA).get()
                .invisibleToPlayerIds().add(getUniqueId()));
    }

    @Override
    public void showPlayer(org.bukkit.entity.Player player) {
        PorePlayer porePlayer = (PorePlayer) player;
        porePlayer.getHandle().offer(porePlayer.getHandle().getOrCreate(INVISIBILITY_DATA).get()
                .invisibleToPlayerIds().remove(getUniqueId()));
    }

    @Override
    public boolean canSee(org.bukkit.entity.Player player) {
        return hasData(INVISIBILITY_DATA) && ((PorePlayer) player).getHandle().get(INVISIBILITY_DATA).get()
                .invisibleToPlayerIds().contains(getUniqueId());
    }

    @Override
    public boolean isFlying() {
        return hasData(FLYING_DATA) && getHandle().get(FLYING_DATA).get().flying().get();
    }

    @Override
    public void setFlying(boolean value) {
        if (value != isFlying()) {
            if (value) {
                getHandle().offer(getHandle().getOrCreate(FLYING_DATA).get().flying().set(true));
            } else {
                getHandle().remove(FLYING_DATA);
            }
        }
    }

    //TODO: movement speeds and flight toggle will be included with the attributes API
    @Override
    public boolean getAllowFlight() {
        throw new NotImplementedException("TODO");
    }

    @Override
    public void setAllowFlight(boolean flight) {
        throw new NotImplementedException("TODO");
    }

    @Override
    public float getWalkSpeed() {
        throw new NotImplementedException("TODO");
    }

    @Override
    public void setWalkSpeed(float value) throws IllegalArgumentException {
        throw new NotImplementedException("TODO");
    }

    @Override
    public float getFlySpeed() {
        throw new NotImplementedException("TODO");
    }

    @Override
    public void setFlySpeed(float value) throws IllegalArgumentException {
        throw new NotImplementedException("TODO");
    }

    @Override
    public void setTexturePack(String url) {
        setResourcePack(url);
    }

    @Override
    public void setResourcePack(String url) {
        try {
            getHandle().sendResourcePack(ResourcePacks.fromUrl(new URL(url)));
        } catch (FileNotFoundException swallow) {
            //TODO: okay to swallow?
        } catch (MalformedURLException swallow) {
            //TODO: okay to swallow?
        }
    }

    @Override
    public Scoreboard getScoreboard() {
        return PoreScoreboard.of(getHandle().getScoreboard());
    }

    @Override
    public void setScoreboard(Scoreboard scoreboard) throws IllegalArgumentException, IllegalStateException {
        getHandle().setScoreboard(((PoreScoreboard) scoreboard).getHandle());
    }

    //TODO: As far as I can tell this is unique to Bukkit, so it'll need to be handled exclusively by Pore.
    @Override
    public boolean isHealthScaled() {
        throw new NotImplementedException("TODO");
    }

    @Override
    public double getHealthScale() {
        throw new NotImplementedException("TODO");
    }

    @Override
    public Entity getSpectatorTarget() {
        throw new NotImplementedException("TODO");
    }

    @Override
    public void setSpectatorTarget(Entity entity) {
        throw new NotImplementedException("TODO");
    }

    @Override
    @SuppressWarnings("deprecation")
    public void sendTitle(String title, String subtitle) {
        getHandle()
                .sendTitle(Titles.of(Texts.legacy().fromUnchecked(title), Texts.legacy().fromUnchecked(subtitle)));
    }

    @Override
    public void resetTitle() {
        getHandle().resetTitle();
    }

    @Override
    public void setHealthScaled(boolean scale) {
        throw new NotImplementedException("TODO");
    }

    @Override
    public void setHealthScale(double scale) throws IllegalArgumentException {
        throw new NotImplementedException("TODO");
    }

    @Override
    @SuppressWarnings("deprecation")
    public void sendMessage(String message) {
        try {
            getHandle().sendMessage(Texts.legacy().from(message));
        } catch (TextMessageException ex) {
            throw new IllegalArgumentException(ex);
        }
    }

    @Override
    @SuppressWarnings("deprecation")
    public void sendMessage(String[] messages) {
        Text[] texts = new Text[messages.length];
        for (int i = 0; i < messages.length; i++) {
            try {
                texts[i] = Texts.legacy().from(messages[i]);
            } catch (TextMessageException ex) {
                throw new IllegalArgumentException(ex);
            }
        }
        this.getHandle().sendMessage(texts);
    }

    @Override
    public Map<String, Object> serialize() {
        Map<String, Object> result = Maps.newLinkedHashMap();
        result.put("name", getName());
        return result;
    }

    @Override
    public void sendPluginMessage(Plugin source, String channel, byte[] message) {
        getHandle().getConnection().sendCustomPayload(source, channel, message);
    }

    @Override
    public Set<String> getListeningPluginChannels() {
        throw new NotImplementedException("TODO");
    }

    @Override
    public UUID getUniqueId() {
        return getHandle().getUniqueId();
    }

    @Override
    public GameMode getGameMode() {
        return GameModeConverter.of(getHandle().getOrCreate(GAME_MODE_DATA).get().type().get());
    }

    @Override
    public void setGameMode(GameMode mode) {
        getHandle().offer(getHandle().getOrCreate(GAME_MODE_DATA).get().type().set(GameModeConverter.of(mode)));
    }
}