public synchronized void setSkin(String skinName) {
        //LogUtil.logInfo("setSkin(" + skinName + ")");
        if (skinName == null || skinName.length() == 0) {
            // Blank values of "skinName" reset skin to default.
            resetSkin();
            return;
        }
        if (isInteger(modelName)) {
            // Skins not supported for block models
            return;
        }
        this.skinName = skinName;

        String lowercaseUrl = skinName.toLowerCase();
        boolean isFullUrl = (lowercaseUrl.startsWith("http://") || lowercaseUrl.startsWith("https://"))
                && lowercaseUrl.endsWith(".png");
        boolean isHumanoid = Model.HUMANOID.equals(modelName);

        String downloadUrl;
        if (isFullUrl) {
            // Full URL was given, download from there.
            downloadUrl = skinName;
        } else {
            // Only the player name was given. Download from skin server.
            downloadUrl = Minecraft.skinServer + skinName.replaceAll("[^a-zA-Z0-9:._]", "") + ".png";
        }

        // Non-humanoid skins are only downloaded if full URL was given.
        // (See "Interaction with ExtPlayerList" in CPE ChangeModel spec)
        if (isHumanoid || isFullUrl) {
            new SkinDownloadThread(this, downloadUrl, skinName, !isHumanoid).start();
        }
    }