Use pagination for //distr and store results. (#496)

This commit is contained in:
wizjany 2019-07-04 19:33:37 -04:00 committed by GitHub
parent a2b3aabbbf
commit 508ece9e0f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 141 additions and 34 deletions

View File

@ -47,16 +47,20 @@ import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
import com.sk89q.worldedit.regions.selector.RegionSelectorType; import com.sk89q.worldedit.regions.selector.RegionSelectorType;
import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.session.request.Request; import com.sk89q.worldedit.session.request.Request;
import com.sk89q.worldedit.util.Countable;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.snapshot.Snapshot; import com.sk89q.worldedit.world.snapshot.Snapshot;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.time.ZoneId; import java.time.ZoneId;
import java.util.Calendar; import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@ -95,6 +99,7 @@ public class LocalSession {
private transient ZoneId timezone = ZoneId.systemDefault(); private transient ZoneId timezone = ZoneId.systemDefault();
private transient BlockVector3 cuiTemporaryBlock; private transient BlockVector3 cuiTemporaryBlock;
private transient EditSession.ReorderMode reorderMode = EditSession.ReorderMode.MULTI_STAGE; private transient EditSession.ReorderMode reorderMode = EditSession.ReorderMode.MULTI_STAGE;
private transient List<Countable<BlockState>> lastDistribution;
// Saved properties // Saved properties
private String lastScript; private String lastScript;
@ -973,4 +978,20 @@ public class LocalSession {
public String getNavWandItem() { public String getNavWandItem() {
return navWandItem; return navWandItem;
} }
/**
* Get the last block distribution stored in this session.
*
* @return block distribution or {@code null}
*/
public List<Countable<BlockState>> getLastDistribution() {
return lastDistribution == null ? null : Collections.unmodifiableList(lastDistribution);
}
/**
* Store a block distribution in this session.
*/
public void setLastDistribution(List<Countable<BlockState>> dist) {
lastDistribution = dist;
}
} }

View File

@ -30,8 +30,8 @@ import com.sk89q.worldedit.command.tool.SelectionWand;
import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissions;
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extension.platform.permission.ActorSelectorLimits; import com.sk89q.worldedit.extension.platform.permission.ActorSelectorLimits;
import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.function.block.BlockDistributionCounter; import com.sk89q.worldedit.function.block.BlockDistributionCounter;
@ -56,14 +56,15 @@ import com.sk89q.worldedit.regions.selector.SphereRegionSelector;
import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.util.Countable;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.formatting.component.BlockDistributionResult;
import com.sk89q.worldedit.util.formatting.component.CommandListBox; import com.sk89q.worldedit.util.formatting.component.CommandListBox;
import com.sk89q.worldedit.util.formatting.component.PaginationBox;
import com.sk89q.worldedit.util.formatting.component.SubtleFormat; import com.sk89q.worldedit.util.formatting.component.SubtleFormat;
import com.sk89q.worldedit.util.formatting.component.TextComponentProducer; import com.sk89q.worldedit.util.formatting.component.TextComponentProducer;
import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor; import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.item.ItemTypes;
@ -71,11 +72,11 @@ import com.sk89q.worldedit.world.storage.ChunkStore;
import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.ArgFlag;
import org.enginehub.piston.annotation.param.Switch; import org.enginehub.piston.annotation.param.Switch;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream; import java.util.stream.Stream;
import static com.sk89q.worldedit.command.util.Logging.LogMode.POSITION; import static com.sk89q.worldedit.command.util.Logging.LogMode.POSITION;
@ -468,13 +469,16 @@ public class SelectionCommands {
desc = "Get the distribution of blocks in the selection" desc = "Get the distribution of blocks in the selection"
) )
@CommandPermissions("worldedit.analysis.distr") @CommandPermissions("worldedit.analysis.distr")
public void distr(Player player, LocalSession session, EditSession editSession, public void distr(Player player, LocalSession session,
@Switch(name = 'c', desc = "Get the distribution of the clipboard instead") @Switch(name = 'c', desc = "Get the distribution of the clipboard instead")
boolean clipboardDistr, boolean clipboardDistr,
@Switch(name = 'd', desc = "Separate blocks by state") @Switch(name = 'd', desc = "Separate blocks by state")
boolean separateStates) throws WorldEditException { boolean separateStates,
@ArgFlag(name = 'p', desc = "Gets page from a previous distribution.", def = "")
Integer page) throws WorldEditException {
List<Countable<BlockState>> distribution; List<Countable<BlockState>> distribution;
if (page == null) {
if (clipboardDistr) { if (clipboardDistr) {
Clipboard clipboard = session.getClipboard().getClipboard(); // throws if missing Clipboard clipboard = session.getClipboard().getClipboard(); // throws if missing
BlockDistributionCounter count = new BlockDistributionCounter(clipboard, separateStates); BlockDistributionCounter count = new BlockDistributionCounter(clipboard, separateStates);
@ -482,36 +486,28 @@ public class SelectionCommands {
Operations.completeBlindly(visitor); Operations.completeBlindly(visitor);
distribution = count.getDistribution(); distribution = count.getDistribution();
} else { } else {
try (EditSession editSession = session.createEditSession(player)) {
distribution = editSession.getBlockDistribution(session.getSelection(player.getWorld()), separateStates); distribution = editSession.getBlockDistribution(session.getSelection(player.getWorld()), separateStates);
} }
}
session.setLastDistribution(distribution);
page = 1;
} else {
distribution = session.getLastDistribution();
if (distribution == null) {
player.printError("No previous distribution.");
return;
}
}
if (distribution.isEmpty()) { // *Should* always be false if (distribution.isEmpty()) { // *Should* always be false
player.printError("No blocks counted."); player.printError("No blocks counted.");
return; return;
} }
// note: doing things like region.getArea is inaccurate for non-cuboids. final int finalPage = page;
int size = distribution.stream().mapToInt(Countable::getAmount).sum(); WorldEditAsyncCommandBuilder.createAndSendMessage(player,
player.print("# total blocks: " + size); () -> new BlockDistributionResult(distribution, separateStates).create(finalPage), null);
for (Countable<BlockState> c : distribution) {
String name = c.getID().getBlockType().getName();
String str;
if (separateStates) {
str = String.format("%-7s (%.3f%%) %s (%s)",
String.valueOf(c.getAmount()),
c.getAmount() / (double) size * 100,
name,
c.getID().getAsString());
} else {
str = String.format("%-7s (%.3f%%) %s (%s)",
String.valueOf(c.getAmount()),
c.getAmount() / (double) size * 100,
name,
c.getID().getBlockType().getId());
}
player.print(str);
}
} }
@Command( @Command(

View File

@ -0,0 +1,90 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.util.formatting.component;
import com.google.common.base.Strings;
import com.sk89q.worldedit.util.Countable;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.event.HoverEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockType;
import java.util.List;
public class BlockDistributionResult extends PaginationBox {
private final List<Countable<BlockState>> distribution;
private final int totalBlocks;
private final boolean separateStates;
public BlockDistributionResult(List<Countable<BlockState>> distribution, boolean separateStates) {
super("Block Distribution", "//distr -p %page%" + (separateStates ? " -d" : ""));
this.distribution = distribution;
// note: doing things like region.getArea is inaccurate for non-cuboids.
this.totalBlocks = distribution.stream().mapToInt(Countable::getAmount).sum();
this.separateStates = separateStates;
setComponentsPerPage(7);
}
@Override
public Component getComponent(int number) {
Countable<BlockState> c = distribution.get(number);
TextComponent.Builder line = TextComponent.builder();
final int count = c.getAmount();
final double perc = count / (double) totalBlocks * 100;
final int maxDigits = (int) (Math.log10(totalBlocks) + 1);
final int curDigits = (int) (Math.log10(count) + 1);
line.append(String.format("%s%.3f%% ", perc < 10 ? " " : "", perc), TextColor.GOLD);
final int space = maxDigits - curDigits;
String pad = Strings.repeat(" ", space == 0 ? 2 : 2 * space + 1);
line.append(String.format("%s%s", count, pad), TextColor.YELLOW);
final BlockState state = c.getID();
final BlockType blockType = state.getBlockType();
TextComponent blockName = TextComponent.of(blockType.getName(), TextColor.LIGHT_PURPLE);
TextComponent toolTip;
if (separateStates && state != blockType.getDefaultState()) {
toolTip = TextComponent.of(state.getAsString(), TextColor.GRAY);
blockName = blockName.append(TextComponent.of("*", TextColor.LIGHT_PURPLE));
} else {
toolTip = TextComponent.of(blockType.getId(), TextColor.GRAY);
}
blockName = blockName.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, toolTip));
line.append(blockName);
return line.build();
}
@Override
public int getComponentsSize() {
return distribution.size();
}
@Override
public Component create(int page) throws InvalidComponentException {
super.getContents().append(TextComponent.of("Total Block Count: " + totalBlocks, TextColor.GRAY))
.append(TextComponent.newline());
return super.create(page);
}
}