com.sk89q.craftbook.sponge.mechanics.area.complex.ComplexArea.java Source code

Java tutorial

Introduction

Here is the source code for com.sk89q.craftbook.sponge.mechanics.area.complex.ComplexArea.java

Source

/*
 * CraftBook Copyright (C) 2010-2018 sk89q <http://www.sk89q.com>
 * CraftBook Copyright (C) 2011-2018 me4502 <http://www.me4502.com>
 * CraftBook Copyright (C) Contributors
 *
 * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
 * License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this program. If not,
 * see <http://www.gnu.org/licenses/>.
 */
package com.sk89q.craftbook.sponge.mechanics.area.complex;

import static com.sk89q.craftbook.sponge.util.locale.TranslationsManager.USE_PERMISSIONS;

import com.google.inject.Inject;
import com.me4502.modularframework.module.Module;
import com.me4502.modularframework.module.guice.ModuleConfiguration;
import com.sk89q.craftbook.core.util.ConfigValue;
import com.sk89q.craftbook.core.util.CraftBookException;
import com.sk89q.craftbook.core.util.PermissionNode;
import com.sk89q.craftbook.core.util.documentation.DocumentationProvider;
import com.sk89q.craftbook.sponge.CraftBookPlugin;
import com.sk89q.craftbook.sponge.mechanics.area.complex.command.DeleteCommand;
import com.sk89q.craftbook.sponge.mechanics.area.complex.command.ListCommand;
import com.sk89q.craftbook.sponge.mechanics.area.complex.command.SaveCommand;
import com.sk89q.craftbook.sponge.mechanics.types.SpongeSignMechanic;
import com.sk89q.craftbook.sponge.util.BlockUtil;
import com.sk89q.craftbook.sponge.util.SignUtil;
import com.sk89q.craftbook.sponge.util.SpongePermissionNode;
import com.sk89q.craftbook.sponge.util.data.CraftBookKeys;
import com.sk89q.craftbook.sponge.util.data.mutable.LastPowerData;
import com.sk89q.craftbook.sponge.util.data.mutable.NamespaceData;
import ninja.leaping.configurate.ConfigurationNode;
import org.apache.commons.lang3.StringUtils;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.block.tileentity.Sign;
import org.spongepowered.api.command.CommandMapping;
import org.spongepowered.api.command.args.GenericArguments;
import org.spongepowered.api.command.spec.CommandSpec;
import org.spongepowered.api.data.key.Keys;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.event.Listener;
import org.spongepowered.api.event.block.InteractBlockEvent;
import org.spongepowered.api.event.block.NotifyNeighborBlockEvent;
import org.spongepowered.api.event.block.tileentity.ChangeSignEvent;
import org.spongepowered.api.event.filter.cause.First;
import org.spongepowered.api.service.permission.PermissionDescription;
import org.spongepowered.api.text.Text;
import org.spongepowered.api.text.format.TextColors;
import org.spongepowered.api.world.LocatableBlock;
import org.spongepowered.api.world.Location;
import org.spongepowered.api.world.World;

import java.util.List;
import java.util.regex.Pattern;

@Module(id = "area", name = "Area", onEnable = "onInitialize", onDisable = "onDisable")
public class ComplexArea extends SpongeSignMechanic implements DocumentationProvider {

    @Inject
    @ModuleConfiguration
    public ConfigurationNode config;

    private SpongePermissionNode createPermissions = new SpongePermissionNode("craftbook.area",
            "Allows the user to create the ToggleArea mechanic.", PermissionDescription.ROLE_USER);
    private SpongePermissionNode createSavePermissions = new SpongePermissionNode("craftbook.area.create.save",
            "Allows the user to create the ToggleArea Save-Only mechanic.", PermissionDescription.ROLE_USER);
    private SpongePermissionNode createGlobalPermissions = new SpongePermissionNode("craftbook.area.create.global",
            "Allows the user to create global ToggleArea mechanics.", PermissionDescription.ROLE_STAFF);
    private SpongePermissionNode createOtherPermissions = new SpongePermissionNode("craftbook.area.create.other",
            "Allows the user to create ToggleArea mechanics with other namespaces.",
            PermissionDescription.ROLE_STAFF);
    private SpongePermissionNode usePermissions = new SpongePermissionNode("craftbook.area.use",
            "Allows the user to use the ToggleArea mechanic.", PermissionDescription.ROLE_USER);

    private SpongePermissionNode commandSavePermissions = new SpongePermissionNode("craftbook.area.save",
            "Allows the user to save ToggleArea regions.", PermissionDescription.ROLE_USER);
    public SpongePermissionNode commandSaveOtherPermissions = new SpongePermissionNode("craftbook.area.save.other",
            "Allows the user to save ToggleArea regions.", PermissionDescription.ROLE_STAFF);
    public SpongePermissionNode commandSaveBypassLimitPermissions = new SpongePermissionNode(
            "craftbook.area.save.bypass-limit", "Allows the user to bypass area limits.",
            PermissionDescription.ROLE_ADMIN);
    private SpongePermissionNode commandDeletePermissions = new SpongePermissionNode("craftbook.area.delete",
            "Allows the user to delete ToggleArea regions.", PermissionDescription.ROLE_USER);
    public SpongePermissionNode commandDeleteOtherPermissions = new SpongePermissionNode(
            "craftbook.area.delete.other", "Allows the user to delete ToggleArea regions.",
            PermissionDescription.ROLE_STAFF);
    private SpongePermissionNode commandListPermissions = new SpongePermissionNode("craftbook.area.list",
            "Allows the user to list ToggleArea regions.", PermissionDescription.ROLE_USER);
    public SpongePermissionNode commandListOtherPermissions = new SpongePermissionNode("craftbook.area.list.other",
            "Allows the user to list ToggleArea regions.", PermissionDescription.ROLE_STAFF);

    public ConfigValue<Integer> maxAreaSize = new ConfigValue<>("maximum-size",
            "The maximum amount of blocks that the saved areas can contain. -1 to disable limit.", 5000);
    public ConfigValue<Integer> maxPerUser = new ConfigValue<>("maximum-per-user",
            "The maximum amount of areas that a namespace can own. 0 to disable limit.", 30);
    public ConfigValue<Boolean> allowRedstone = new ConfigValue<>("allow-redstone",
            "Whether to allow redstone to be used to trigger this mechanic or not", true);

    private CommandMapping areaCommandMapping;

    private static final Pattern MARKER_PATTERN = Pattern.compile("^-[A-Za-z0-9_]*?-$");

    @Override
    public void onInitialize() throws CraftBookException {
        super.onInitialize();

        maxAreaSize.load(config);
        maxPerUser.load(config);
        allowRedstone.load(config);

        CommandSpec saveCommand = CommandSpec.builder()
                .description(Text.of("Command to save selected WorldEdit regions."))
                .permission(commandSavePermissions.getNode()).executor(new SaveCommand(this))
                .arguments(GenericArguments.onlyOne(GenericArguments.string(Text.of("id"))),
                        GenericArguments
                                .optional(GenericArguments.onlyOne(GenericArguments.string(Text.of("namespace")))))
                .build();

        CommandSpec deleteCommand = CommandSpec.builder()
                .description(Text.of("Command to delete saved ToggleArea regions."))
                .permission(commandDeletePermissions.getNode()).executor(new DeleteCommand(this))
                .arguments(GenericArguments.onlyOne(GenericArguments.string(Text.of("id"))),
                        GenericArguments
                                .optional(GenericArguments.onlyOne(GenericArguments.string(Text.of("namespace")))))
                .build();

        CommandSpec listCommand = CommandSpec.builder()
                .description(Text.of("Command to list saved ToggleArea regions."))
                .permission(commandListPermissions.getNode()).executor(new ListCommand(this))
                .arguments(GenericArguments
                        .optional(GenericArguments.onlyOne(GenericArguments.string(Text.of("namespace")))))
                .build();

        CommandSpec mainAreaCommand = CommandSpec.builder()
                .description(Text.of("Base command for the ToggleArea system.")).child(saveCommand, "save")
                .child(deleteCommand, "delete", "del").child(listCommand, "list").build();

        areaCommandMapping = Sponge.getCommandManager()
                .register(CraftBookPlugin.inst(), mainAreaCommand, "area", "togglearea").orElse(null);
    }

    @Override
    public void onDisable() {
        super.onDisable();

        if (areaCommandMapping != null) {
            Sponge.getCommandManager().removeMapping(areaCommandMapping);
        }
    }

    @Listener
    public void onSignChange(ChangeSignEvent event, @First Player player) {
        for (String line : getValidSigns()) {
            if (SignUtil.getTextRaw(event.getText(), 1).equalsIgnoreCase(line)) {
                if (!createPermissions.hasPermission(player)
                        && !("[SaveArea]".equals(line) && createSavePermissions.hasPermission(player))) {
                    player.sendMessage(
                            Text.of(TextColors.RED, "You do not have permission to create this mechanic!"));
                    event.setCancelled(true);
                } else {
                    List<Text> lines = event.getText().lines().get();
                    lines.set(1, Text.of(line));

                    String namespace = lines.get(0).toPlain();
                    boolean personal = false;
                    if ("global".equals(namespace.toLowerCase())) {
                        if (!createGlobalPermissions.hasPermission(player)) {
                            player.sendMessage(Text.of(TextColors.RED,
                                    "You do not have permission to create global ToggleAreas!"));
                            event.setCancelled(true);
                            return;
                        } else {
                            namespace = "GLOBAL";
                        }
                    } else if (namespace.trim().isEmpty() || !createOtherPermissions.hasPermission(player)) {
                        namespace = player.getUniqueId().toString();
                        personal = true;
                    }

                    lines.set(0, Text.of(personal ? player.getName() : namespace));

                    if (!isValidArea(namespace, lines.get(2).toPlain(), lines.get(3).toPlain())) {
                        player.sendMessage(Text.of(TextColors.RED, "This area is missing!"));
                        event.setCancelled(true);
                        return;
                    }

                    event.getTargetTile().offer(new NamespaceData(namespace));

                    event.getText().set(Keys.SIGN_LINES, lines);

                    player.sendMessage(Text.of(TextColors.YELLOW, "Created ToggleArea!"));
                }

                break;
            }
        }
    }

    @Listener
    public void onBlockUpdate(NotifyNeighborBlockEvent event, @First LocatableBlock source) {
        if (!allowRedstone.getValue())
            return;

        if (!SignUtil.isSign(source.getLocation()))
            return;
        Location<World> block = source.getLocation();
        Sign sign = (Sign) block.getTileEntity().get();

        if (isMechanicSign(sign)) {
            Player player = event.getCause().first(Player.class).orElse(null);
            if (player != null) {
                if (!usePermissions.hasPermission(player)) {
                    player.sendMessage(USE_PERMISSIONS);
                    return;
                }
            }

            boolean isPowered = BlockUtil.getBlockPowerLevel(block).orElse(0) > 0;
            boolean wasPowered = block.get(CraftBookKeys.LAST_POWER).orElse(0) > 0;

            if (isPowered != wasPowered) {
                triggerMechanic(block, sign, isPowered);
                block.offer(new LastPowerData(isPowered ? 15 : 0));
            }
        }
    }

    @Listener
    public void onRightClick(InteractBlockEvent.Secondary.MainHand event, @First Player human) {
        event.getTargetBlock().getLocation().ifPresent(location -> {
            if (isValid(location)) {
                location.getTileEntity().ifPresent((sign -> {
                    if (human == null || usePermissions.hasPermission(human)) {
                        if (triggerMechanic(location, (Sign) sign, null)) {
                            event.setCancelled(true);
                            if (human != null)
                                human.sendMessage(Text.of(TextColors.YELLOW, "Toggled!"));
                        }
                    } else {
                        human.sendMessage(USE_PERMISSIONS);
                    }
                }));
            }
        });
    }

    public boolean triggerMechanic(Location<World> location, Sign sign, Boolean forceState) {
        boolean save = "[SaveArea]".equals(SignUtil.getTextRaw(sign, 1));

        String namespace = sign.get(CraftBookKeys.NAMESPACE).orElse(null);
        String id = StringUtils.replace(SignUtil.getTextRaw(sign, 2), "-", "").toLowerCase();
        String inactiveID = StringUtils.replace(SignUtil.getTextRaw(sign, 3), "-", "").toLowerCase();

        if (namespace == null) {
            return false;
        }

        try {
            CuboidCopy copy;

            boolean state = checkToggleState(sign);
            if (forceState != null) {
                state = forceState;
            }

            if (state) {
                copy = CopyManager.load(location.getExtent(), namespace, id);

                if (save) {
                    copy.copy();
                    CopyManager.save(namespace, id, copy);
                }

                if (!inactiveID.isEmpty() && !"--".equals(inactiveID)) {
                    copy = CopyManager.load(location.getExtent(), namespace, inactiveID);
                    copy.paste();
                } else {
                    copy.clear();
                }

                setToggleState(sign, false);
            } else {
                if (save && !inactiveID.isEmpty() && !"--".equals(inactiveID)) {
                    copy = CopyManager.load(location.getExtent(), namespace, inactiveID);
                    copy.copy();
                    CopyManager.save(namespace, inactiveID, copy);
                }

                copy = CopyManager.load(location.getExtent(), namespace, id);
                copy.paste();
                setToggleState(sign, true);
            }

            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }

    private static boolean isValidArea(String namespace, String areaOn, String areaOff) {
        if (CopyManager.isExistingArea(CraftBookPlugin.inst().getWorkingDirectory(), namespace, areaOn)) {
            if (areaOff == null || areaOff.isEmpty() || "--".equals(areaOff))
                return true;
            if (CopyManager.isExistingArea(CraftBookPlugin.inst().getWorkingDirectory(), namespace, areaOff))
                return true;
        }
        return false;
    }

    private static boolean checkToggleState(Sign sign) {
        String line3 = SignUtil.getTextRaw(sign, 2).toLowerCase();
        String line4 = SignUtil.getTextRaw(sign, 3).toLowerCase();
        return MARKER_PATTERN.matcher(line3).matches()
                || !("--".equals(line4) || MARKER_PATTERN.matcher(line4).matches());
    }

    private static void setToggleState(Sign sign, boolean state) {
        int toToggleOn = state ? 2 : 3;
        int toToggleOff = state ? 3 : 2;
        List<Text> lines = sign.lines().get();
        lines.set(toToggleOff, Text.of(sign.lines().get(toToggleOff).toPlain().replace("-", "")));
        lines.set(toToggleOn, Text.of("-", sign.lines().get(toToggleOn), "-"));
        sign.offer(Keys.SIGN_LINES, lines);
    }

    public String[] getValidSigns() {
        return new String[] { "[SaveArea]", "[Area]" };
    }

    @Override
    public String getName() {
        return "ToggleArea";
    }

    @Override
    public SpongePermissionNode getCreatePermission() {
        return createPermissions;
    }

    @Override
    public String getPath() {
        return "mechanics/togglearea";
    }

    @Override
    public ConfigValue<?>[] getConfigurationNodes() {
        return new ConfigValue<?>[] { maxAreaSize, maxPerUser, allowRedstone };
    }

    @Override
    public PermissionNode[] getPermissionNodes() {
        return new PermissionNode[] { createPermissions, usePermissions, createSavePermissions,
                createGlobalPermissions, createOtherPermissions, commandSavePermissions,
                commandSaveOtherPermissions, commandSaveBypassLimitPermissions, commandListPermissions,
                commandListOtherPermissions, commandDeletePermissions, commandDeleteOtherPermissions };
    }
}