Add /rg migrateheights. (#1857)

Closes #1856.
This commit is contained in:
wizjany 2021-12-02 15:44:25 -05:00 committed by GitHub
parent 703146bc18
commit 81750e191d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 177 additions and 2 deletions

View File

@ -65,6 +65,7 @@ import com.sk89q.worldguard.protection.managers.RemovalStrategy;
import com.sk89q.worldguard.protection.managers.migration.DriverMigration;
import com.sk89q.worldguard.protection.managers.migration.MigrationException;
import com.sk89q.worldguard.protection.managers.migration.UUIDMigration;
import com.sk89q.worldguard.protection.managers.migration.WorldHeightMigration;
import com.sk89q.worldguard.protection.managers.storage.DriverType;
import com.sk89q.worldguard.protection.managers.storage.RegionDriver;
import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion;
@ -1068,6 +1069,62 @@ public final class RegionCommands extends RegionCommandsBase {
}
}
/**
* Migrate regions that went from 0-255 to new world heights.
*
* @param args the arguments
* @param sender the sender
* @throws CommandException any error
*/
@Command(aliases = {"migrateheights"},
usage = "[world]", max = 1,
flags = "yw:",
desc = "Migrate regions from old height limits to new height limits")
public void migrateHeights(CommandContext args, Actor sender) throws CommandException {
// Check permissions
if (!getPermissionModel(sender).mayMigrateRegionHeights()) {
throw new CommandPermissionsException();
}
if (!args.hasFlag('y')) {
throw new CommandException("This command is potentially dangerous.\n" +
"Please ensure you have made a backup of your data, and then re-enter the command with -y tacked on at the end to proceed.");
}
World world = null;
try {
world = checkWorld(args, sender, 'w');
} catch (CommandException ignored) {
}
LoggerToChatHandler handler = null;
Logger minecraftLogger = null;
if (sender instanceof LocalPlayer) {
handler = new LoggerToChatHandler(sender);
handler.setLevel(Level.ALL);
minecraftLogger = Logger.getLogger("com.sk89q.worldguard");
minecraftLogger.addHandler(handler);
}
try {
RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer();
RegionDriver driver = container.getDriver();
WorldHeightMigration migration = new WorldHeightMigration(driver, WorldGuard.getInstance().getFlagRegistry(), world);
container.migrate(migration);
sender.print("Migration complete!");
} catch (MigrationException e) {
log.log(Level.WARNING, "Failed to migrate", e);
throw new CommandException("Error encountered while migrating: " + e.getMessage());
} finally {
if (minecraftLogger != null) {
minecraftLogger.removeHandler(handler);
}
}
}
/**
* Teleport to a region
*

View File

@ -63,7 +63,11 @@ public class RegionPermissionModel extends AbstractPermissionModel {
public boolean mayMigrateRegionNames() {
return hasPluginPermission("region.migrateuuid");
}
public boolean mayMigrateRegionHeights() {
return hasPluginPermission("region.migrateheights");
}
public boolean mayDefine() {
return hasPluginPermission("region.define");
}

View File

@ -72,7 +72,7 @@ abstract class AbstractMigration implements Migration {
* @param store the region store
* @throws MigrationException on migration error
*/
protected abstract void migrate(RegionDatabase store)throws MigrationException;
protected abstract void migrate(RegionDatabase store) throws MigrationException;
/**
* Called after migration has successfully completed.

View File

@ -0,0 +1,114 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldGuard 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.worldguard.protection.managers.migration;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.managers.storage.RegionDatabase;
import com.sk89q.worldguard.protection.managers.storage.RegionDriver;
import com.sk89q.worldguard.protection.managers.storage.StorageException;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import javax.annotation.Nullable;
import java.lang.reflect.Field;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
public class WorldHeightMigration extends AbstractMigration {
private static final Logger log = Logger.getLogger(WorldHeightMigration.class.getCanonicalName());
private static final Field minField;
private static final Field maxField;
static {
try {
minField = ProtectedRegion.class.getDeclaredField("min");
minField.setAccessible(true);
maxField = ProtectedRegion.class.getDeclaredField("max");
maxField.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new ExceptionInInitializerError(new MigrationException("Migrator broke.", e));
}
}
private final FlagRegistry flagRegistry;
private final World world;
private int changed = 0;
public WorldHeightMigration(RegionDriver driver, FlagRegistry flagRegistry, @Nullable World world) {
super(driver);
this.flagRegistry = flagRegistry;
this.world = world;
}
@Override
protected void migrate(RegionDatabase store) throws MigrationException {
if (world != null && !store.getName().equals(world.getName())) return;
log.log(Level.INFO, "Migrating regions in '" + store.getName() + "' to new height limits...");
Set<ProtectedRegion> regions;
try {
regions = store.loadAll(flagRegistry);
} catch (StorageException e) {
throw new MigrationException("Failed to load region data for the world '" + store.getName() + "'", e);
}
int min = -64;
int max = 319;
World world = WorldGuard.getInstance().getPlatform().getMatcher().getWorldByName(store.getName());
if (world != null) {
min = world.getMinY();
max = world.getMaxY();
// in theory someone could run a data pack that keeps their world height
// at the old defaults...? either way if this is the case there are no changes to make.
if (min == 0 && max == 255) return;
}
for (ProtectedRegion region : regions) {
if (region.getMinimumPoint().getBlockY() <= 0
&& region.getMaximumPoint().getBlockY() >= 255) {
expand(region, min, max);
changed++;
}
}
try {
store.saveAll(regions);
} catch (StorageException e) {
throw new MigrationException("Failed to save region data after migration of the world '" + store.getName() + "'", e);
}
}
private static void expand(ProtectedRegion region, int min, int max) throws MigrationException {
try {
minField.set(region, region.getMinimumPoint().withY(min));
maxField.set(region, region.getMaximumPoint().withY(max));
region.setDirty(true);
} catch (IllegalAccessException e) {
throw new MigrationException("Migrator broke.", e);
}
}
@Override
protected void postMigration() {
log.log(Level.INFO, "A total of " + changed + " top-to-bottom regions were vertically expanded.");
}
}