package org.ultramine.mods.hawkeye; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.ultramine.mods.hawkeye.database.DataManager; import org.ultramine.mods.hawkeye.entry.DataEntry; import org.ultramine.mods.hawkeye.util.HawkUtil; import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.eventhandler.SubscribeEvent; import cpw.mods.fml.common.gameevent.TickEvent; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.world.World; import net.minecraftforge.common.util.BlockSnapshot; /** * Runnable class for performing a data rollback. This class should always be * run in a separate thread to avoid impacting on server performance * * @author oliverw92 */ public class Rollback { private static final Logger log = LogManager.getLogger(); private final PlayerSession session; private Iterator<DataEntry> rollbackQueue; private final List<DataEntry> undo = new ArrayList<DataEntry>(); private RollbackType rollbackType = RollbackType.GLOBAL; /** * @param session * {@link PlayerSession} to retrieve rollback results from */ public Rollback(RollbackType rollbackType, PlayerSession session) { this.rollbackType = rollbackType; this.session = session; rollbackQueue = session.getRollbackResults().iterator(); //Check that we actually have results if(!rollbackQueue.hasNext()) { HawkUtil.sendMessage(session.getSender(), "&cNo results found to rollback"); return; } HawkUtil.debug("Starting rollback of " + session.getRollbackResults().size() + " results"); //Start rollback session.setDoingRollback(true); HawkUtil.sendMessage(session.getSender(), "&cAttempting to rollback &7" + session.getRollbackResults().size() + "&c results"); FMLCommonHandler.instance().bus().register(this); } /** * Run the rollback. Contains appropriate methods of catching errors and * notifying the player */ @SubscribeEvent public void onServerTick(TickEvent.ServerTickEvent e) { if(e.phase == TickEvent.Phase.END) return; //Start rollback process int i = 0; while(i < 200 && rollbackQueue.hasNext()) { DataEntry entry = rollbackQueue.next(); //If the action can't be rolled back, skip this entry if(entry.getType() == null || !entry.getType().canRollback()) continue; //If the world doesn't exist, skip this entry World world = HawkEye.getWorld(entry.getWorld()); if(world == null) continue; //Get some data from the entry BlockSnapshot state = BlockSnapshot.getBlockSnapshot(world, (int) entry.getX(), (int) entry.getY(), (int) entry.getZ()); //Attempt global rollback if(rollbackType == RollbackType.GLOBAL) { boolean addUndo; try { addUndo = entry.rollback(world); } catch(Exception exc) { addUndo = true; log.error("Error while rollbacking entry at ["+entry.getWorld()+"]("+entry.getX()+", "+entry.getY()+", "+entry.getZ()+")", exc); } if(addUndo) { entry.setUndoState(state); undo.add(entry); } } //Local rollback preview else if(rollbackType == RollbackType.LOCAL && entry.rollbackPlayer(world, (EntityPlayerMP)session.getSender())) { entry.setUndoState(state); undo.add(entry); } i++; } //Check if rollback is finished if(!rollbackQueue.hasNext()) { //End timer FMLCommonHandler.instance().bus().unregister(this); session.setDoingRollback(false); session.setRollbackResults(undo); //Store undo results and notify player if(rollbackType == RollbackType.GLOBAL) { HawkUtil.sendMessage(session.getSender(), "&cRollback complete, &7" + undo.size() + "&c edits performed"); HawkUtil.sendMessage(session.getSender(), "&cUndo this rollback using &7/hawk undo"); //Delete data if told to if(HawkEye.instance.config.general.deleteDataOnRollback) DataManager.deleteEntries(undo); } else { HawkUtil.sendMessage(session.getSender(), "&cRollback preview complete, &7" + undo.size() + "&c edits performed to you"); HawkUtil.sendMessage(session.getSender(), "&cType &7/hawk apply&c to make these changes permanent or &7/hawk cancel&c to cancel"); } HawkUtil.debug("Rollback complete, " + undo.size() + " edits performed"); } } public enum RollbackType { GLOBAL, LOCAL } }