/*
* CraftBook Copyright (C) 2010-2017 sk89q <http://www.sk89q.com>
* CraftBook Copyright (C) 2011-2017 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;
import static com.sk89q.craftbook.sponge.util.locale.TranslationsManager.USE_PERMISSIONS;
import com.me4502.modularframework.module.ModuleWrapper;
import com.sk89q.craftbook.core.util.ConfigValue;
import com.sk89q.craftbook.sponge.CraftBookPlugin;
import com.sk89q.craftbook.sponge.mechanics.blockbags.AdminBlockBag;
import com.sk89q.craftbook.sponge.mechanics.blockbags.BlockBag;
import com.sk89q.craftbook.sponge.mechanics.blockbags.BlockBagManager;
import com.sk89q.craftbook.sponge.mechanics.blockbags.EmbeddedBlockBag;
import com.sk89q.craftbook.sponge.mechanics.blockbags.IdentifiableBlockBag;
import com.sk89q.craftbook.sponge.util.data.mutable.BlockBagData;
import com.sk89q.craftbook.sponge.util.data.mutable.EmbeddedBlockBagData;
import com.sk89q.craftbook.sponge.mechanics.types.SpongeSignMechanic;
import com.sk89q.craftbook.sponge.util.BlockFilter;
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.locale.TranslationsManager;
import com.sk89q.craftbook.sponge.util.type.TypeTokens;
import ninja.leaping.configurate.ConfigurationNode;
import org.spongepowered.api.block.tileentity.Sign;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.entity.living.Humanoid;
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.cause.NamedCause;
import org.spongepowered.api.event.filter.cause.First;
import org.spongepowered.api.event.filter.cause.Named;
import org.spongepowered.api.service.permission.PermissionDescription;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.text.Text;
import org.spongepowered.api.text.TranslatableText;
import org.spongepowered.api.text.translation.ResourceBundleTranslation;
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.Optional;
import javax.annotation.Nullable;
public abstract class SimpleArea extends SpongeSignMechanic {
SpongePermissionNode createPermissions = new SpongePermissionNode("craftbook." + getName().toLowerCase(), "Allows the user to create the " + getName() + " mechanic.", PermissionDescription.ROLE_USER);
SpongePermissionNode usePermissions = new SpongePermissionNode("craftbook." + getName().toLowerCase() + ".use", "Allows the user to use the " + getName() + " mechanic.", PermissionDescription.ROLE_USER);
ConfigValue<List<BlockFilter>> allowedBlocks = new ConfigValue<>("allowed-blocks", "A list of blocks that can be used.", getDefaultBlocks(), new TypeTokens.BlockFilterListTypeToken());
ConfigValue<Boolean> allowRedstone = new ConfigValue<>("allow-redstone", "Whether to allow redstone to be used to trigger this mechanic or not", true);
TranslatableText missingOtherEnd = TranslatableText.of(new ResourceBundleTranslation("area.missing-other-end", TranslationsManager.getResourceBundleFunction()));
void loadCommonConfig(ConfigurationNode config) {
allowedBlocks.load(config);
allowRedstone.load(config);
}
void registerCommonPermissions() {
createPermissions.register();
usePermissions.register();
}
@Override
public SpongePermissionNode getCreatePermission() {
return createPermissions;
}
@Listener
public void onPlayerInteract(InteractBlockEvent.Secondary.MainHand event, @Named(NamedCause.SOURCE) Humanoid human) {
event.getTargetBlock().getLocation().ifPresent(location -> {
if (isValid(location)) {
location.getTileEntity().ifPresent((sign -> {
if ((!(human instanceof Subject) || usePermissions.hasPermission((Subject) human))) {
if (triggerMechanic(location, (Sign) sign, human, null)) {
event.setCancelled(true);
}
} else if (human instanceof CommandSource) {
((CommandSource) human).sendMessage(USE_PERMISSIONS);
}
}));
}
});
}
@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().get(NamedCause.SOURCE, 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, player, isPowered);
block.offer(new LastPowerData(isPowered ? 15 : 0));
}
}
}
@Override
public boolean verifyLines(Location<World> location, List<Text> lines, @Nullable Player player) {
String line0 = SignUtil.getTextRaw(lines.get(0));
if (!line0.isEmpty()) {
Optional<ModuleWrapper> moduleWrapper = CraftBookPlugin.spongeInst().moduleController.getModule("blockbag");
if (moduleWrapper.isPresent() && moduleWrapper.get().isEnabled()) {
if ("ADMIN".equals(line0)) {
if ((player == null || ((BlockBagManager) moduleWrapper.get().getModule().get()).adminPermissions.hasPermission(player))) {
location.offer(new BlockBagData(-1));
} else {
lines.set(0, Text.of());
}
}
}
}
return super.verifyLines(location, lines, player);
}
public BlockBag getBlockBag(Location<World> location) {
Optional<ModuleWrapper> moduleWrapper = CraftBookPlugin.spongeInst().moduleController.getModule("blockbag");
if (moduleWrapper.isPresent() && moduleWrapper.get().isEnabled()) {
BlockBagManager manager = ((BlockBagManager) moduleWrapper.get().getModule().get());
Optional<Long> blockBag = location.get(CraftBookKeys.BLOCK_BAG);
if (blockBag.isPresent()) {
Optional<IdentifiableBlockBag> foundBlockBag = blockBag.map(manager::getBlockBag);
if (foundBlockBag.isPresent()) {
return foundBlockBag.get();
}
}
Optional<EmbeddedBlockBag> embeddedBlockBag = location.get(CraftBookKeys.EMBEDDED_BLOCK_BAG);
if (embeddedBlockBag.isPresent()) {
return embeddedBlockBag.get();
}
EmbeddedBlockBag actualBlockBag = new EmbeddedBlockBag();
manager.addBlockBag(actualBlockBag);
location.offer(new EmbeddedBlockBagData(actualBlockBag));
return actualBlockBag;
}
return AdminBlockBag.INSTANCE;
}
/**
* Triggers the mechanic.
*
* @param block The block the mechanic is being triggered at
* @param sign The sign of the mechanic
* @param human The triggering human, if applicable
* @param forceState If the mechanic should forcibly enter a specific state
*/
public abstract boolean triggerMechanic(Location<World> block, Sign sign, @Nullable Humanoid human, @Nullable Boolean forceState);
public abstract List<BlockFilter> getDefaultBlocks();
}