/*
* Copyright 2011 Tyler Blair. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and contributors and should not be interpreted as representing official policies,
* either expressed or implied, of anybody else.
*/
package com.griefcraft.modules.admin;
import com.griefcraft.lwc.LWC;
import com.griefcraft.model.History;
import com.griefcraft.model.Protection;
import com.griefcraft.scripting.JavaModule;
import com.griefcraft.scripting.event.LWCCommandEvent;
import com.griefcraft.util.Colors;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.command.CommandSender;
import java.util.Iterator;
import java.util.List;
/**
* Rebuild a LWC database re: Feb 15 2012 incident
*/
public class AdminRebuild extends JavaModule {
@Override
public void onCommand(LWCCommandEvent event) {
if (event.isCancelled()) {
return;
}
if (!event.hasFlag("a", "admin")) {
return;
}
LWC lwc = event.getLWC();
CommandSender sender = event.getSender();
String[] args = event.getArgs();
if (!args[0].equals("rebuild")) {
return;
}
// we have the right command
event.setCancelled(true);
if (args.length == 1 || !args[1].equalsIgnoreCase("confirm")) {
sender.sendMessage("This will attempt to rebuild the entire LWC database from scratch.");
sender.sendMessage("This WILL repair most of the database, regarding the incident on February 15, 2012. However, please note that old protections may be restored.");
sender.sendMessage("This may take some time so it is recommended it is ran inside the console.");
sender.sendMessage(Colors.Red + "Are you sure you would like to go ahead? Use /lwc admin rebuild confirm to confirm.");
} else if (args[1].equalsIgnoreCase("confirm")) {
rebuildDatabase(sender);
}
}
/**
* Attempt to rebuild the database with what we have
*
* @param sender
*/
private void rebuildDatabase(CommandSender sender) {
LWC lwc = LWC.getInstance();
sender.sendMessage("Now rebuilding the LWC database.");
// Get all of the currently active history objects
lwc.getProtectionCache().clear();
List<History> fullHistory = lwc.getPhysicalDatabase().loadHistory(History.Status.ACTIVE);
sender.sendMessage("Loaded " + fullHistory.size() + " history objects");
// Our start time
long start = System.currentTimeMillis();
// The amount of protections we created
int created = 0;
// The amount of protections we failed to create
int failed = 0;
Iterator iter = fullHistory.iterator();
while (iter.hasNext()) {
History history = (History) iter.next();
// Is it active?
if (history.getProtection() != null) {
iter.remove();
continue;
}
// Coordinates
int x = history.getX();
int y = history.getY();
int z = history.getZ();
// Very old history object
if (x == 0 && y == 0 && z == 0) {
iter.remove();
continue;
}
// Protection's creator
String creator = history.getString("creator");
if (creator == null) {
sender.sendMessage(String.format("Unable to match owner at Id:%d", history.getId()));
failed ++;
iter.remove();
continue;
}
// Bruteforce that shit, yo
Block block = findProtectableBlock(x, y, z);
if (block == null) {
sender.sendMessage(String.format("Unable to match block at Id:%d [%d, %d, %d] (this is probably OK)", history.getId(), x, y, z));
failed ++;
iter.remove();
continue;
}
// Create the protection!
Protection protection = lwc.getPhysicalDatabase().registerProtection(block.getTypeId(), Protection.Type.PRIVATE,
block.getWorld().getName(), creator, "", x, y, z);
if (protection == null) {
sender.sendMessage(String.format("Failed to create protection at Id:%d", history.getId()));
failed ++;
iter.remove();
continue;
}
// Hell yeah
created ++;
history.remove();
protection.saveNow();
iter.remove();
// Clean up the cache, we want to conserve as much memory as possible at this time
lwc.getProtectionCache().clear();
}
int total = created + failed; // the total amount of history objects operated on
long runningTime = System.currentTimeMillis() - start;
int runningTimeSeconds = (int) runningTime / 1000;
float ratio = ((float) created / (total)) * 100;
sender.sendMessage(String.format("LWC rebuild complete (%ds). %.2f%% conversion ratio; %d success and %d failures", runningTimeSeconds, ratio, created, failed));
}
/**
* Look for a protectable block in each world. Return the first one found. Starts in the main world.
*
* @param x
* @param y
* @param z
* @return
*/
private Block findProtectableBlock(int x, int y, int z) {
LWC lwc = LWC.getInstance();
Server server = Bukkit.getServer();
for (World world : server.getWorlds()) {
Block block = world.getBlockAt(x, y, z);
if (lwc.isProtectable(block)) {
// Woo!
return block;
}
}
// Bad news...
return null;
}
}