package org.mctourney.autoreferee.util.worldsearch;
import java.util.Set;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.Validate;
import org.bukkit.ChunkSnapshot;
import org.bukkit.Material;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.Vector;
import org.mctourney.autoreferee.util.BlockData;
import com.google.common.collect.Sets;
/**
* Consumes: ObjectiveExhaustionMasterTask.snapshots<br>
* Output: ObjectiveExhaustionMasterTask.found<br>
* Output: ObjectiveExhaustionMasterTask.foundContainers<br>
* Cancellation: Self-cancels upon master.all_snapshots_added and queue empty
*
* Searches the ChunkSnapshots for the goal blocks.
*
* @author kane
*
*/
public class WorkerAsyncSearchSnapshots extends BukkitRunnable
{
public volatile boolean finished = false;
private ObjectiveExhaustionMasterTask master;
public WorkerAsyncSearchSnapshots(ObjectiveExhaustionMasterTask task)
{
master = task;
}
@Override
public void run()
{
// pre-clear, pass it on later
boolean wasInterrupted = Thread.interrupted();
try
{
// Blocking run until everything's available
while (!master.all_snapshots_added)
{
consume(master.snapshots.take());
}
// Finish off by listening to special value
ChunkSnapshot snap;
while ((snap = master.snapshots.poll()) != null)
{
consume(snap);
}
}
catch (IllegalArgumentException poisonSignal)
{
// thrown if null is recieved, which means we're done
}
catch (InterruptedException e)
{
e.printStackTrace();
wasInterrupted = true;
}
// Re-add null to the list, for the other workers to take
master.snapshots.offer(null);
finished = true;
if (wasInterrupted) // pass it on
Thread.currentThread().interrupt();
}
private void consume(ChunkSnapshot snap)
{
Validate.notNull(snap); // send stop signal if poison-value
Set<BlockData> goals = master.searching; // safe due to COW
int[] interesting = buildInteresting(goals);
int baseX = snap.getX() << 4;
int baseZ = snap.getZ() << 4;
for (int sy = 0; sy < 16; sy++)
{
if (snap.isSectionEmpty(sy))
continue;
for (int py = sy << 4; py < (sy << 4) + 16; py++)
for (int iz = 0; iz < 16; iz++)
for (int ix = 0; ix < 16; ix++)
{
int block = snap.getBlockTypeId(ix, py, iz);
if (ArrayUtils.contains(interesting, block))
{
Vector pos = new Vector(baseX + ix, py, baseZ + iz);
BlockData bd = new BlockData(Material.getMaterial(block), (byte) snap.getBlockData(ix, py, iz));
for (BlockData data : goals)
if (data.equals(bd))
master.found.add(new _Entry<BlockData, Vector>(data, pos));
}
}
}
}
// Often this will just return the equivalent of new int[] { 35 } but whatever.
private static int[] buildInteresting(Set<BlockData> goals)
{
Set<Integer> filterGoals = Sets.newHashSet();
for (BlockData data : goals)
{
filterGoals.add(data.getMaterial().getId());
}
return ArrayUtils.toPrimitive(filterGoals.toArray(new Integer[filterGoals.size()]));
}
}