Package net.aufdemrand.denizen.objects

Source Code of net.aufdemrand.denizen.objects.dCuboid$LocationPair

package net.aufdemrand.denizen.objects;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.aufdemrand.denizen.Settings;
import net.aufdemrand.denizen.objects.notable.Notable;
import net.aufdemrand.denizen.objects.notable.NotableManager;
import net.aufdemrand.denizen.objects.notable.Note;
import net.aufdemrand.denizen.objects.properties.Property;
import net.aufdemrand.denizen.objects.properties.PropertyParser;
import net.aufdemrand.denizen.tags.Attribute;
import net.aufdemrand.denizen.utilities.Utilities;
import net.aufdemrand.denizen.utilities.blocks.SafeBlock;
import net.aufdemrand.denizen.utilities.debugging.dB;

import net.aufdemrand.denizen.utilities.depends.Depends;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.npc.NPC;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;

public class dCuboid implements dObject, Cloneable, Notable, Adjustable {

    // Cloning
    @Override
    public dCuboid clone() throws CloneNotSupportedException {
        return (dCuboid) super.clone();
    }

    /////////////////////
    //   STATIC METHODS
    /////////////////

    public static List<dCuboid> getNotableCuboidsContaining(Location location) {
        List<dCuboid> cuboids = new ArrayList<dCuboid>();
        for (dCuboid cuboid : NotableManager.getAllType(dCuboid.class))
            if (cuboid.isInsideCuboid(location))
                cuboids.add(cuboid);

        return cuboids;
    }


    //////////////////
    //    OBJECT FETCHER
    ////////////////

    final static Pattern item_by_saved = Pattern.compile("(cu@)(.+)");
    /**
     * Gets a Location Object from a string form of id,x,y,z,world
     * or a dScript argument (location:)x,y,z,world. If including an Id,
     * this location will persist and can be recalled at any time.
     *
     * @param string  the string or dScript argument String
     * @return  a Location, or null if incorrectly formatted
     *
     */
    @Fetchable("cu")
    public static dCuboid valueOf(String string) {
        if (string == null) return null;

        ////////
        // Match location formats

        // Split values
        dList positions = dList.valueOf(string.replace("cu@", ""));

        // If there's a | and the first two points look like locations, assume it's a valid location-list constructor.
        if (positions.size() > 1
                && dLocation.matches(positions.get(0))
                && dLocation.matches(positions.get(1))) {
            if (positions.size() % 2 != 0) {
                dB.echoError("valueOf dCuboid returning null (Uneven number of locations): '" + string + "'.");
                return null;
            }

            // Form a cuboid to add to
            dCuboid toReturn = new dCuboid();

            // Add to the cuboid
            for (int i = 0; i < positions.size(); i += 2) {
                dLocation pos_1 = dLocation.valueOf(positions.get(i));
                dLocation pos_2 = dLocation.valueOf(positions.get(i + 1));

                // Must be valid locations
                if (pos_1 == null || pos_2 == null) {
                    dB.echoError("valueOf in dCuboid returning null (null locations): '" + string + "'.");
                    return null;
                }
                toReturn.addPair(pos_1, pos_2);
            }

            // Ensure validity and return the created cuboid
            if (toReturn.pairs.size() > 0)
                return toReturn;
        }

        ////////
        // Match @object format for Notable dCuboids
        Matcher m;

        m = item_by_saved.matcher(string);

        if (m.matches() && NotableManager.isType(m.group(2), dCuboid.class))
            return (dCuboid) NotableManager.getSavedObject(m.group(2));

        dB.echoError("valueOf dCuboid returning null: " + string);

        return null;
    }

    // regex patterns used for matching
    final static Pattern location_by_saved = Pattern.compile("(cu@)?(.+)");
    // The regex below: optional-"|" + "<#.#>," x3 + <text> + "|" + "<#.#>," x3 + <text> -- repeating
    final static Pattern location =
            Pattern.compile("(\\|?([\\d\\.]+,){3}[\\w\\s]+\\|([\\d\\.]+,){3}[\\w\\s]+)+",
                    Pattern.CASE_INSENSITIVE);


    public static boolean matches(String string) {
        // Starts with cu@? Assume match.
        if (string.toLowerCase().startsWith("cu@")) return true;

        Matcher m;

        // Check for named cuboid: cu@notable_cuboid
        m = location_by_saved.matcher(string);
        if (m.matches() && NotableManager.isType(m.group(2), dCuboid.class)) return true;

        // Check for standard cuboid format: cu@x,y,z,world|x,y,z,world|...
        m = location.matcher(string.replace("cu@", ""));
        return m.matches();
    }


    ///////////////
    //  LocationPairs
    /////////////


    public static class LocationPair {
        dLocation  low;
        dLocation high;
        dLocation point_1;
        dLocation point_2;
        int x_distance;
        int y_distance;
        int z_distance;

        public LocationPair(dLocation point_1, dLocation point_2) {
            this.point_1 = point_1;
            this.point_2 = point_2;
            regenerate();
        }

        public void changePoint(int number, dLocation point) {
            if (number == 1)
                this.point_1 = point;
            else if (number == 2)
                this.point_2 = point;
            regenerate();
        }

        public void regenerate() {
            World world = point_1.getWorld();

            // Find the low and high locations based on the points
            // specified
            int x_high = (point_1.getBlockX() >= point_2.getBlockX()
                    ? point_1.getBlockX() : point_2.getBlockX());
            int x_low = (point_1.getBlockX() <= point_2.getBlockX()
                    ? point_1.getBlockX() : point_2.getBlockX());

            int y_high = (point_1.getBlockY() >= point_2.getBlockY()
                    ? point_1.getBlockY() : point_2.getBlockY());
            int y_low = (point_1.getBlockY() <= point_2.getBlockY()
                    ? point_1.getBlockY() : point_2.getBlockY());

            int z_high = (point_1.getBlockZ() >= point_2.getBlockZ()
                    ? point_1.getBlockZ() : point_2.getBlockZ());
            int z_low = (point_1.getBlockZ() <= point_2.getBlockZ()
                    ? point_1.getBlockZ() : point_2.getBlockZ());

            // Specify defining locations to the pair
            low = new dLocation(world, x_low, y_low, z_low);
            high = new dLocation(world, x_high, y_high, z_high);
            generateDistances();
        }

        public void generateDistances() {
            x_distance = high.getBlockX() - low.getBlockX();
            y_distance = high.getBlockY() - low.getBlockY();
            z_distance = high.getBlockZ() - low.getBlockZ();
        }
    }


    ///////////////////
    //  Constructors/Instance Methods
    //////////////////

    // Location Pairs (low, high) that make up the dCuboid
    List<LocationPair> pairs = new ArrayList<LocationPair>();

    // Only put dMaterials in filter.
    ArrayList<dObject> filter = new ArrayList<dObject>();

    /**
     * Construct the cuboid without adding pairs
     * ONLY use this if addPair will be called immediately after!
     */
    public dCuboid() {
    }

    public dCuboid(Location point_1, Location point_2) {
        addPair(point_1, point_2);
    }


    public void addPair(Location point_1, Location point_2) {
        if (point_1.getWorld() != point_2.getWorld()) {
            dB.echoError("Tried to make cross-world cuboid!");
            return;
        }
        if (pairs.size() > 0 && point_1.getWorld() != getWorld()) {
            dB.echoError("Tried to make cross-world cuboid set!");
            return;
        }
        // Make a new pair
        LocationPair pair = new LocationPair(new dLocation(point_1), new dLocation(point_2));
        // Add it to the Cuboid pairs list
        pairs.add(pair);
    }


    public boolean isInsideCuboid(Location location) {
        for (LocationPair pair : pairs) {
            if (!location.getWorld().equals(pair.low.getWorld()))
                continue;
            if (!Utilities.isBetween(pair.low.getBlockX(), pair.high.getBlockX(), location.getBlockX()))
                continue;
            if (!Utilities.isBetween(pair.low.getBlockY(), pair.high.getBlockY(), location.getBlockY()))
                continue;
            if (Utilities.isBetween(pair.low.getBlockZ(), pair.high.getBlockZ(), location.getBlockZ()))
                return true;
        }

        // Does not match any of the pairs
        return false;
    }


    public dCuboid addBlocksToFilter(List<dMaterial> addl) {
        filter.addAll(addl);
        return this;
    }


    public dCuboid removeBlocksFromFilter(List<dMaterial> addl) {
        filter.removeAll(addl);
        return this;
    }


    public dCuboid removeFilter() {
        filter.clear();
        return this;
    }


    public dCuboid setAsFilter(List<dMaterial> list) {
        filter.clear();
        filter.addAll(list);
        return this;
    }

    public dList getOutline() {

        //    +-----2
        //   /|    /|
        //  +-----+ |
        //  | +---|-+
        //  |/    |/
        //  1-----+
        int max = Settings.blockTagsMaxBlocks();
        int index = 0;

        dList list = new dList();

        for (LocationPair pair : pairs) {

            dLocation loc_1 = pair.low;
            dLocation loc_2 = pair.high;
            int y_distance = pair.y_distance;
            int z_distance = pair.z_distance;
            int x_distance = pair.x_distance;

            for (int y = loc_1.getBlockY(); y <= loc_1.getBlockY() + y_distance; y++) {
                list.add(new dLocation(loc_1.getWorld(),
                        loc_1.getBlockX(),
                        y,
                        loc_1.getBlockZ()).identify());

                list.add(new dLocation(loc_1.getWorld(),
                        loc_2.getBlockX(),
                        y,
                        loc_2.getBlockZ()).identify());

                list.add(new dLocation(loc_1.getWorld(),
                        loc_1.getBlockX(),
                        y,
                        loc_2.getBlockZ()).identify());

                list.add(new dLocation(loc_1.getWorld(),
                        loc_2.getBlockX(),
                        y,
                        loc_1.getBlockZ()).identify());
                index++;
                if (index > max)
                    return list;
            }

            for (int x = loc_1.getBlockX(); x <= loc_1.getBlockX() + x_distance; x++) {
                list.add(new dLocation(loc_1.getWorld(),
                        x,
                        loc_1.getBlockY(),
                        loc_1.getBlockZ()).identify());

                list.add(new dLocation(loc_1.getWorld(),
                        x,
                        loc_1.getBlockY(),
                        loc_2.getBlockZ()).identify());

                list.add(new dLocation(loc_1.getWorld(),
                        x,
                        loc_2.getBlockY(),
                        loc_2.getBlockZ()).identify());

                list.add(new dLocation(loc_1.getWorld(),
                        x,
                        loc_2.getBlockY(),
                        loc_1.getBlockZ()).identify());
                index++;
                if (index > max)
                    return list;
            }

            for (int z = loc_1.getBlockZ(); z <= loc_1.getBlockZ() + z_distance; z++) {
                list.add(new dLocation(loc_1.getWorld(),
                        loc_1.getBlockX(),
                        loc_1.getBlockY(),
                        z).identify());

                list.add(new dLocation(loc_1.getWorld(),
                        loc_2.getBlockX(),
                        loc_2.getBlockY(),
                        z).identify());

                list.add(new dLocation(loc_1.getWorld(),
                        loc_1.getBlockX(),
                        loc_2.getBlockY(),
                        z).identify());

                list.add(new dLocation(loc_1.getWorld(),
                        loc_2.getBlockX(),
                        loc_1.getBlockY(),
                        z).identify());
                index++;
                if (index > max)
                    return list;
            }
        }

        return list;
    }


    public dList getBlocks() {
        return getBlocks(null);
    }

    private boolean matchesMaterialList(Location loc, List<dMaterial> materials) {
        if (materials == null)
            return true;
        dMaterial mat = dMaterial.getMaterialFrom(loc.getBlock().getType(), loc.getBlock().getData());
        for (dMaterial material: materials) {
            if (mat.equals(material)) {
                return true;
            }
        }
        return false;
    }

    public dList getBlocks(List<dMaterial> materials) {
        int max = Settings.blockTagsMaxBlocks();
        dLocation loc;
        dList list = new dList();
        int index = 0;

        for (LocationPair pair : pairs) {

            dLocation loc_1 = pair.low;
            int y_distance = pair.y_distance;
            int z_distance = pair.z_distance;
            int x_distance = pair.x_distance;

            for (int x = 0; x != x_distance + 1; x++) {
                for (int z = 0; z != z_distance + 1; z++) {
                    for (int y = 0; y != y_distance + 1; y++) {
                        loc = new dLocation(loc_1.clone().add(x, y, z));
                        if (!filter.isEmpty()) {
                            // Check filter
                            for (dObject material : filter) {
                                if (loc.getBlock().getType().name().equalsIgnoreCase(((dMaterial) material)
                                        .getMaterial().name())) {
                                    if (matchesMaterialList(loc, materials)) {
                                        list.add(loc.identify());
                                    }
                                }
                            }
                        }
                        else {
                            if (matchesMaterialList(loc, materials)) {
                                list.add(loc.identify());
                            }
                        }
                        index++;
                        if (index > max)
                            return list;
                    }
                }
            }

        }

        return list;
    }

    public List<dLocation> getBlockLocations() {
        int max = Settings.blockTagsMaxBlocks();
        dLocation loc;
        List<dLocation> list = new ArrayList<dLocation>();
        int index = 0;

        for (LocationPair pair : pairs) {

            dLocation loc_1 = pair.low;
            int y_distance = pair.y_distance;
            int z_distance = pair.z_distance;
            int x_distance = pair.x_distance;

            for (int x = 0; x != x_distance + 1; x++) {
                for (int z = 0; z != z_distance + 1; z++) {
                    for (int y = 0; y != y_distance + 1; y++) {
                        loc = new dLocation(loc_1.clone()
                                .add(x, y, z));
                        if (!filter.isEmpty()) {
                            // Check filter
                            for (dObject material : filter)
                                if (loc.getBlock().getType().name().equalsIgnoreCase(((dMaterial) material)
                                        .getMaterial().name()))
                                    list.add(loc);
                        }
                        else
                            list.add(loc);
                        index++;
                        if (index > max)
                            return list;
                    }
                }
            }

        }

        return list;
    }


    public dList getSpawnableBlocks() {
        return getSpawnableBlocks(null);
    }

    /**
     * Returns a dList of dLocations with 2 vertical blocks of air
     * that are safe for players and similar entities to spawn in,
     * but ignoring blocks in midair
     *
     * @return  The dList
     */

    public dList getSpawnableBlocks(List<dMaterial> mats) {
        int max = Settings.blockTagsMaxBlocks();
        dLocation loc;
        dList list = new dList();
        int index = 0;

        for (LocationPair pair : pairs) {

            dLocation loc_1 = pair.low;
            int y_distance = pair.y_distance;
            int z_distance = pair.z_distance;
            int x_distance = pair.x_distance;

            for (int x = 0; x != x_distance + 1; x++) {
                for (int z = 0; z != z_distance + 1; z++) {
                    for (int y = 0; y != y_distance; y++) {

                        loc = new dLocation(loc_1.clone()
                                .add(x, y, z));

                        if (SafeBlock.blockIsSafe(loc.getBlock().getType())
                                && SafeBlock.blockIsSafe(loc.clone().add(0, 1, 0).getBlock().getType())
                                && loc.clone().add(0, -1, 0).getBlock().getType().isSolid()
                                && matchesMaterialList(loc.clone().add(0, -1, 0), mats)) {
                            // Get the center of the block, so the entity won't suffocate
                            // inside the edges for a couple of seconds
                            loc.add(0.5, 0, 0.5);
                            list.add(loc.identify());
                        }
                        index++;
                        if (index > max)
                            return list;
                    }
                }
            }
        }

        return list;
    }

    public World getWorld() {
        if (pairs.size() == 0)
            return null;
        return pairs.get(0).high.getWorld();
    }

    public dLocation getHigh(int index) {
        if (index < 0)
            return null;
        if (index >= pairs.size())
            return null;
        return pairs.get(index).high;
    }

    public dLocation getLow(int index) {
        if (index < 0)
            return null;
        if (index >= pairs.size())
            return null;
        return pairs.get(index).low;
    }

    ///////////////////
    // Notable
    ///////////////////


    @Override
    public boolean isUnique() {
        return NotableManager.isSaved(this);
    }


    @Override
    @Note("Cuboids")
    public String getSaveObject() {
        return identifyFull().substring(3);
    }

    @Override
    public void makeUnique(String id) { NotableManager.saveAs(this, id); }

    @Override
    public void forget() {
        NotableManager.remove(this);
    }

    /////////////////////
    // dObject
    ////////////////////


    String prefix = "Cuboid";


    @Override
    public String getObjectType() {
        return "cuboid";
    }


    @Override
    public String getPrefix() {
        return prefix;
    }


    @Override
    public dCuboid setPrefix(String prefix) {
        this.prefix = prefix;
        return this;
    }


    @Override
    public String debug() {
        return (isUnique()
                ? "<G>" + prefix + "='<A>" + NotableManager.getSavedId(this)
                + "(<Y>" + identify()+ "<A>)<G>'  "
                : "<G>" + prefix + "='<Y>" + identify() + "<G>'  ");
    }


    @Override
    public String identify() {
        if (isUnique())
            return "cu@" + NotableManager.getSavedId(this);

        else {
            return identifyFull();
        }
    }


    @Override
    public String identifySimple() {
        return identify();
    }

    public String identifyFull() {
        StringBuilder sb = new StringBuilder();
        sb.append("cu@");

        for (LocationPair pair : pairs) {
            if (pair.low.getWorld() == null || pair.high.getWorld() == null) {
                dB.echoError("Null world for cuboid, returning invalid identity!");
                return "cu@null";
            }
            sb.append(pair.low.getBlockX()).append(',').append(pair.low.getBlockY())
                    .append(',').append(pair.low.getBlockZ()).append(',').append(pair.low.getWorld().getName())
                    .append('|').append(pair.high.getBlockX()).append(',').append(pair.high.getBlockY())
                    .append(',').append(pair.high.getBlockZ()).append(',').append(pair.high.getWorld().getName()).append('|');
        }

        return sb.toString().substring(0, sb.toString().length() - 1);
    }


    @Override
    public String toString() {
        return identify();
    }

    /////////////////////
    // dObject Attributes
    /////////////////////


    @Override
    public String getAttribute(Attribute attribute) {
        if (attribute == null) return null;

        // <--[tag]
        // @attribute <cu@cuboid.get_blocks[<material>...]>
        // @returns dList(dLocation)
        // @description
        // Returns each block location within the dCuboid.
        // Optionally, specify a list of materials to only return locations
        // with that block type.
        // -->
        if (attribute.startsWith("get_blocks")) {
            if (attribute.hasContext(1))
                return new dList(getBlocks(dList.valueOf(attribute.getContext(1)).filter(dMaterial.class)))
                        .getAttribute(attribute.fulfill(1));
            else
                return new dList(getBlocks())
                        .getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <cu@cuboid.members_size>
        // @returns Element(Number)
        // @description
        // Returns the number of cuboids defined in the dCuboid.
        // -->
        if (attribute.startsWith("members_size"))
            return new Element(pairs.size())
                    .getAttribute(attribute.fulfill(1));

        // <--[tag]
        // @attribute <cu@cuboid.get_member[<#>]>
        // @returns dCuboid
        // @description
        // Returns a new dCuboid of a single member of this dCuboid. Just specify an index.
        // -->
        if (attribute.startsWith("get_member")) {
            int member = attribute.getIntContext(1);
            if (member < 1)
                member = 1;
            if (member > pairs.size())
                member = pairs.size();
            return new dCuboid(pairs.get(member - 1).low, pairs.get(member - 1).high)
                    .getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <cu@cuboid.get_spawnable_blocks[<Material>|...]>
        // @returns dList(dLocation)
        // @description
        // Returns each dLocation within the dCuboid that is
        // safe for players or similar entities to spawn in.
        // Optionally, specify a list of materials to only return locations
        // with that block type.
        // -->
        if (attribute.startsWith("get_spawnable_blocks")) {
            if (attribute.hasContext(1))
                return new dList(getSpawnableBlocks(dList.valueOf(attribute.getContext(1)).filter(dMaterial.class)))
                        .getAttribute(attribute.fulfill(1));
            else
                return new dList(getSpawnableBlocks())
                        .getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <cu@cuboid.get_outline>
        // @returns dList(dLocation)
        // @description
        // Returns each block location on the outline of the dCuboid.
        // -->
        if (attribute.startsWith("get_outline"))
            return new dList(getOutline())
                    .getAttribute(attribute.fulfill(1));

        // <--[tag]
        // @attribute <cu@cuboid.filter>
        // @returns dList(dLocation)
        // @description
        // Returns the block locations from the dCuboid's filter.
        // -->
        if (attribute.startsWith("filter"))
            return new dList(filter)
                    .getAttribute(attribute.fulfill(1));

        // Tag deprecated in favor of l@location.is_within
        if (attribute.startsWith("is_within")
                && attribute.hasContext(1)) {
            dLocation loc = dLocation.valueOf(attribute.getContext(1));
            if (loc != null)
                return new Element(isInsideCuboid(loc))
                        .getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <cu@cuboid.intersects[<cuboid>]>
        // @returns Element(Boolean)
        // @description
        // Returns whether this cuboid and another intersect.
        // -->
        if (attribute.startsWith("intersects")
                && attribute.hasContext(1)) {
            dCuboid cub2 = dCuboid.valueOf(attribute.getContext(1));
            if (cub2 != null) {
                boolean intersects = false;
                for (LocationPair pair: pairs) {
                    for (LocationPair pair2: cub2.pairs) {
                        if (pair2.low.getX() <= pair.high.getX()
                                && pair2.low.getY() <= pair.high.getY()
                                && pair2.low.getZ() <= pair.high.getZ()
                                && pair2.high.getX() >= pair.low.getX()
                                && pair2.high.getY() >= pair.low.getY()
                                && pair2.high.getZ() >= pair.low.getZ()) {
                            intersects = true;
                            break;
                        }
                    }
                }
                return new Element(intersects).getAttribute(attribute.fulfill(1));
            }
        }

        // <--[tag]
        // @attribute <cu@cuboid.center[<index>]>
        // @returns dLocation
        // @description
        // Returns the center location. If a single-member dCuboid, no index is required.
        // If wanting the center of a specific member, just specify an index.
        // -->
        if (attribute.startsWith("center")) {
            LocationPair pair;
            if (!attribute.hasContext(1))
                pair = pairs.get(0);
            else {
                int member = attribute.getIntContext(1);
                if (member < 1)
                    member = 1;
                if (member > pairs.size())
                    member = pairs.size();
                pair = pairs.get(member - 1);
            }
            Location base = pair.high.clone().add(pair.low.clone());
            base.setX(base.getX() / 2);
            base.setY(base.getY() / 2);
            base.setZ(base.getZ() / 2);
            return new dLocation(base).getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <cu@cuboid.max[<index>]>
        // @returns dLocation
        // @description
        // Returns the highest-numbered corner location. If a single-member dCuboid, no
        // index is required. If wanting the max of a specific member, just specify an index.
        // -->
        if (attribute.startsWith("max")) {
            if (!attribute.hasContext(1))
                return pairs.get(0).high.getAttribute(attribute.fulfill(1));
            else {
                int member = attribute.getIntContext(1);
                if (member < 1)
                    member = 1;
                if (member > pairs.size())
                    member = pairs.size();
                return pairs.get(member - 1).high.getAttribute(attribute.fulfill(1));
            }
        }

        // <--[tag]
        // @attribute <cu@cuboid.min[<index>]>
        // @returns dLocation
        // @description
        // Returns the lowest-numbered corner location. If a single-member dCuboid, no
        // index is required. If wanting the min of a specific member, just specify an index.
        // -->
        if (attribute.startsWith("min")) {
            if (!attribute.hasContext(1))
                return pairs.get(0).low.getAttribute(attribute.fulfill(1));
            else {
                int member = attribute.getIntContext(1);
                if (member < 1)
                    member = 1;
                if (member > pairs.size())
                    member = pairs.size();
                return pairs.get(member - 1).low.getAttribute(attribute.fulfill(1));
            }
        }

        // <--[tag]
        // @attribute <cu@cuboid.include[<location>]>
        // @returns dCuboid
        // @description
        // Expands the first member of the dCuboid to contain the given location, and returns the expanded cuboid.
        // -->
        if (attribute.startsWith("include")
                && attribute.hasContext(1)) {
            try {
                dLocation loc = dLocation.valueOf(attribute.getContext(1));
                dCuboid cuboid = this.clone();
                if (loc != null) {
                    if (loc.getX() < cuboid.pairs.get(0).low.getX())
                        cuboid.pairs.get(0).low = new dLocation(cuboid.pairs.get(0).low.getWorld(), loc.getX(), cuboid.pairs.get(0).low.getY(), cuboid.pairs.get(0).low.getZ());
                    if (loc.getY() < cuboid.pairs.get(0).low.getY())
                        cuboid.pairs.get(0).low = new dLocation(cuboid.pairs.get(0).low.getWorld(), cuboid.pairs.get(0).low.getX(), loc.getY(), cuboid.pairs.get(0).low.getZ());
                    if (loc.getZ() < cuboid.pairs.get(0).low.getZ())
                        cuboid.pairs.get(0).low = new dLocation(cuboid.pairs.get(0).low.getWorld(), cuboid.pairs.get(0).low.getX(), cuboid.pairs.get(0).low.getY(), loc.getZ());
                    if (loc.getX() > cuboid.pairs.get(0).high.getX())
                        cuboid.pairs.get(0).high = new dLocation(cuboid.pairs.get(0).high.getWorld(), loc.getX(), cuboid.pairs.get(0).high.getY(), cuboid.pairs.get(0).high.getZ());
                    if (loc.getY() > cuboid.pairs.get(0).high.getY())
                        cuboid.pairs.get(0).high = new dLocation(cuboid.pairs.get(0).high.getWorld(), cuboid.pairs.get(0).high.getX(), loc.getY(), cuboid.pairs.get(0).high.getZ());
                    if (loc.getZ() > cuboid.pairs.get(0).high.getZ())
                        cuboid.pairs.get(0).high = new dLocation(cuboid.pairs.get(0).high.getWorld(), cuboid.pairs.get(0).high.getX(), cuboid.pairs.get(0).high.getY(), loc.getZ());
                    return cuboid.getAttribute(attribute.fulfill(1));
                }
            }
            catch (CloneNotSupportedException ex) { }
        }

        // <--[tag]
        // @attribute <cu@cuboid.list_players>
        // @returns dList(dPlayer)
        // @description
        // Gets a list of all players currently within the dCuboid.
        // -->
        if (attribute.startsWith("list_players")) {
            ArrayList<dPlayer> players = new ArrayList<dPlayer>();
            for (Player player : Bukkit.getOnlinePlayers())
                if (isInsideCuboid(player.getLocation()))
                    players.add(dPlayer.mirrorBukkitPlayer(player));
            return new dList(players).getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <cu@cuboid.list_npcs>
        // @returns dList(dNPC)
        // @description
        // Gets a list of all NPCs currently within the dCuboid.
        // -->
        if (attribute.startsWith("list_npcs") && Depends.citizens != null) {
            ArrayList<dNPC> npcs = new ArrayList<dNPC>();
            for (NPC npc : CitizensAPI.getNPCRegistry()) {
                dNPC dnpc = dNPC.mirrorCitizensNPC(npc);
                if (isInsideCuboid(dnpc.getLocation()))
                    npcs.add(dnpc);
            }
            return new dList(npcs).getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <cu@cuboid.list_entities[<entity>|...]>
        // @returns dList(dEntity)
        // @description
        // Gets a list of all entities currently within the dCuboid, with
        // an optional search parameter for the entity type.
        // -->
        if (attribute.startsWith("list_entities")) {
            ArrayList<dEntity> entities = new ArrayList<dEntity>();
            dList types = new dList();
            if (attribute.hasContext(1)) {
                types = dList.valueOf(attribute.getContext(1));
            }
            for (Entity ent : getWorld().getEntities()) {
                dEntity current = new dEntity(ent);
                if (ent.isValid() && isInsideCuboid(ent.getLocation())) {
                    if (!types.isEmpty()) {
                        for (String type : types) {
                            if (current.identifySimpleType().equalsIgnoreCase(type)) {
                                entities.add(current);
                                break;
                            }
                        }
                    }
                    else
                        entities.add(new dEntity(ent));
                }
            }
            return new dList(entities).getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <cu@cuboid.list_living_entities>
        // @returns dList(dEntity)
        // @description
        // Gets a list of all living entities currently within the dCuboid.
        // -->
        if (attribute.startsWith("list_living_entities")) {
            ArrayList<dEntity> entities = new ArrayList<dEntity>();
            for (Entity ent : getWorld().getLivingEntities()) {
                if (ent.isValid() && isInsideCuboid(ent.getLocation())
                        && (Depends.citizens == null || !CitizensAPI.getNPCRegistry().isNPC(ent)))
                    entities.add(new dEntity(ent));
            }
            return new dList(entities).getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <cu@cuboid.list_chunks>
        // @returns dList(dChunk)
        // @description
        // Gets a list of all chunks entirely within the dCuboid.
        // -->
        if (attribute.startsWith("list_chunks")) {
            Set<Chunk> chunks = new HashSet<Chunk>();
            for (LocationPair pair : pairs) {
                int minY = pair.low.getBlockY();
                Chunk minChunk = pair.low.getChunk();
                if (isInsideCuboid(new Location(getWorld(), minChunk.getX()*16, minY, minChunk.getZ()*16)))
                    chunks.add(minChunk);
                Chunk maxChunk = pair.high.getChunk();
                if (isInsideCuboid(new Location(getWorld(), maxChunk.getX()*16+15, minY, maxChunk.getZ()*16+15)))
                    chunks.add(maxChunk);
                dB.log("min:" + minChunk.getX() + "," + minChunk.getZ());
                dB.log("max:" + maxChunk.getX() + "," + maxChunk.getZ());
                for(int x = minChunk.getX()+1; x <= maxChunk.getX()-1; x++) {
                    for(int z = minChunk.getZ()+1; z <= maxChunk.getZ()-1; z++) {
                        chunks.add(getWorld().getChunkAt(x, z));
                    }
                }
            }
            dList list = new dList();
            for (Chunk chunk : chunks)
                list.add(new dChunk(chunk).identify());
            return list.getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <cu@cuboid.list_partial_chunks>
        // @returns dList(dChunk)
        // @description
        // Gets a list of all chunks partially or entirely within the dCuboid.
        // -->
        if (attribute.startsWith("list_partial_chunks")) {
            Set<Chunk> chunks = new HashSet<Chunk>();
            for (LocationPair pair : pairs) {
                Chunk minChunk = pair.low.getChunk();
                Chunk maxChunk = pair.high.getChunk();
                dB.log("min:" + minChunk.getX() + "," + minChunk.getZ());
                dB.log("max:" + maxChunk.getX() + "," + maxChunk.getZ());
                for (int x = minChunk.getX(); x <= maxChunk.getX(); x++) {
                    for (int z = minChunk.getZ(); z <= maxChunk.getZ(); z++) {
                        chunks.add(getWorld().getChunkAt(x, z));
                    }
                }
            }
            dList list = new dList();
            for (Chunk chunk : chunks)
                list.add(new dChunk(chunk).identify());
            return list.getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <cu@cuboid.notable_name>
        // @returns Element
        // @description
        // Gets the name of a Notable dCuboid. If the cuboid isn't noted,
        // this is null.
        // -->
        if (attribute.startsWith("notable_name")) {
            return new Element(NotableManager.getSavedId(this)).getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <cu@cuboid.full>
        // @returns Element
        // @group conversion
        // @description
        // Returns a full reusable item identification for this cuboid, with extra, generally useless data.
        // -->
        if (attribute.startsWith("full"))
            return new Element(identifyFull()).getAttribute(attribute.fulfill(1));

        // <--[tag]
        // @attribute <cu@cuboid.type>
        // @returns Element
        // @description
        // Always returns 'Cuboid' for dCuboid objects. All objects fetchable by the Object Fetcher will return the
        // type of object that is fulfilling this attribute.
        // -->
        if (attribute.startsWith("type")) {
            return new Element("Cuboid").getAttribute(attribute.fulfill(1));
        }
        // Iterate through this object's properties' attributes
        for (Property property : PropertyParser.getProperties(this)) {
            String returned = property.getAttribute(attribute);
            if (returned != null) return returned;
        }

        return new Element(identify()).getAttribute(attribute);
    }

    public void applyProperty(Mechanism mechanism) {
        adjust(mechanism);
    }

    @Override
    public void adjust(Mechanism mechanism) {

        Element value = mechanism.getValue();

        // TODO: Should cuboids have mechanisms? Aren't tags sufficient?

        // <--[mechanism]
        // @object dCuboid
        // @name outset
        // @input Element(Number)
        // @description
        // 'Outsets' the area of a dCuboid by the number specified, or 1 if not
        // specified. Example: - adjust cu@my_cuboid outset:5
        // Outsetting a cuboid expands it in all directions. Use negative numbers
        // to 'inset' instead.
        // @tags
        // <cu@cuboid.get_outline>
        // -->
        if (mechanism.matches("outset")) {
            int mod = 1;
            if (value != null && mechanism.requireInteger("Invalid integer specified. Assuming '1'."))
                mod = value.asInt();
            for (LocationPair pair : pairs) {
                pair.low.add(-1 * mod, -1 * mod, -1 * mod);
                pair.high.add(mod, mod, mod);
                // Modify the locations, need to readjust the distances generated
                pair.generateDistances();
            }

            // TODO: Make sure negative numbers don't collapse (and invert) the Cuboid
            return;
        }

        // <--[mechanism]
        // @object dCuboid
        // @name expand
        // @input Element(Number)
        // @description
        // Expands the area of a dCuboid by the number specified, or 1 if not
        // specified, in a specified direction. Example: - adjust cu@my_cuboid expand:5|north
        // Use negative numbers to 'reduce' instead.
        // @tags
        // <e@entity.location.direction>
        // <e@entity.location.pitch>
        // <cu@cuboid.get_outline>
        // -->
        if (mechanism.matches("expand")) {
            int mod = 1;
            if (value != null && mechanism.requireInteger("Invalid integer specified. Assuming '1'."))
                mod = value.asInt();
            for (LocationPair pair : pairs) {
                pair.low.add(-1 * mod, -1 * mod, -1 * mod);
                pair.high.add(mod, mod, mod);
                // Modify the locations, need to readjust the distances generated
                pair.generateDistances();
            }

            // TODO: Make sure negative numbers don't collapse (and invert)
            // the Cuboid
            return;
        }

        // <--[mechanism]
        // @object dCuboid
        // @name set_location
        // @input Element(Number)
        // @description
        // Sets one of two defining locations. dCuboid will take the location into
        // account when recalculating the low and high locations as well as distances
        // belonging to the cuboid.
        // @tags
        // <cu@cuboid.low>
        // <cu@cuboid.high>
        // -->
        if (mechanism.matches("set_location")) {
            int mod = 1;
            if (value != null && mechanism.requireInteger("Invalid integer specified. Assuming '1'."))
                mod = value.asInt();
            for (LocationPair pair : pairs) {
                pair.low.add(-1 * mod, -1 * mod, -1 * mod);
                pair.high.add(mod, mod, mod);
                // Modify the locations, need to readjust the distances generated
                pair.generateDistances();
            }

            // TODO: Make sure negative numbers don't collapse (and invert)
            // the Cuboid
            return;
        }

        // Iterate through this object's properties' mechanisms
        for (Property property : PropertyParser.getProperties(this)) {
            property.adjust(mechanism);
            if (mechanism.fulfilled())
                break;
        }

        if (!mechanism.fulfilled())
            mechanism.reportInvalid();

    }
}
TOP

Related Classes of net.aufdemrand.denizen.objects.dCuboid$LocationPair

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.