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.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.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 Rebuild { private static final Logger log = LogManager.getLogger(); private final PlayerSession session; private Iterator<DataEntry> rebuildQueue; private final List<DataEntry> undo = new ArrayList<DataEntry>(); private int counter = 0; /** * @param session * {@link PlayerSession} to retrieve rebuild results from */ public Rebuild(PlayerSession session) { this.session = session; rebuildQueue = session.getRollbackResults().iterator(); //Check that we actually have results if(!rebuildQueue.hasNext()) { HawkUtil.sendMessage(session.getSender(), "&cNo results found to rebuild"); return; } HawkUtil.debug("Starting rebuild of " + session.getRollbackResults().size() + " results"); //Start rollback session.setDoingRollback(true); HawkUtil.sendMessage(session.getSender(), "&cAttempting to rebuild &7" + session.getRollbackResults().size() + "&c results"); FMLCommonHandler.instance().bus().register(this); } @SubscribeEvent public void onServerTick(TickEvent.ServerTickEvent e) { if(e.phase == TickEvent.Phase.END) return; //Start rollback process int i = 0; while(i < 200 && rebuildQueue.hasNext()) { i++; DataEntry entry = rebuildQueue.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; BlockSnapshot state = BlockSnapshot.getBlockSnapshot(world, (int) entry.getX(), (int) entry.getY(), (int) entry.getZ()); //Rebuild it boolean addUndo; try { addUndo = entry.rebuild(world); } catch(Exception exc) { addUndo = true; log.error("Error while rebuild entry at ["+entry.getWorld()+"]("+entry.getX()+", "+entry.getY()+", "+entry.getZ()+")", exc); } if(addUndo) { entry.setUndoState(state); undo.add(entry); } counter++; } //Check if rollback is finished if(!rebuildQueue.hasNext()) { //End timer FMLCommonHandler.instance().bus().unregister(this); session.setDoingRollback(false); session.setRollbackResults(undo); HawkUtil.sendMessage(session.getSender(), "&cRebuild complete, &7" + counter + "&c edits performed"); HawkUtil.sendMessage(session.getSender(), "&cUndo this rebuild using &7/hawk undo"); HawkUtil.debug("Rebuild complete, " + counter + " edits performed"); } } }