Better claiming. Step 1.
This commit is contained in:
		@@ -1,5 +1,7 @@
 | 
			
		||||
package com.massivecraft.factions.cmd;
 | 
			
		||||
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
 | 
			
		||||
import com.massivecraft.factions.Perm;
 | 
			
		||||
import com.massivecraft.factions.cmd.arg.ARFaction;
 | 
			
		||||
import com.massivecraft.factions.entity.Faction;
 | 
			
		||||
@@ -50,7 +52,8 @@ public class CmdFactionsAutoClaim extends FactionsCommand
 | 
			
		||||
		msender.setAutoClaimFaction(forFaction);
 | 
			
		||||
		
 | 
			
		||||
		msg("<i>Now auto-claiming land for <h>%s<i>.", forFaction.describeTo(msender));
 | 
			
		||||
		msender.tryClaim(forFaction, PS.valueOf(me), true, true);
 | 
			
		||||
		
 | 
			
		||||
		msender.tryClaim(forFaction, Collections.singletonList(PS.valueOf(me).getChunk(true)));
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
@@ -1,11 +1,13 @@
 | 
			
		||||
package com.massivecraft.factions.cmd;
 | 
			
		||||
 | 
			
		||||
import java.util.LinkedHashSet;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import com.massivecraft.factions.Perm;
 | 
			
		||||
import com.massivecraft.factions.cmd.arg.ARFaction;
 | 
			
		||||
import com.massivecraft.factions.entity.Faction;
 | 
			
		||||
import com.massivecraft.factions.entity.MConf;
 | 
			
		||||
import com.massivecraft.factions.entity.MPerm;
 | 
			
		||||
import com.massivecraft.factions.task.SpiralTask;
 | 
			
		||||
import com.massivecraft.massivecore.cmd.arg.ARInteger;
 | 
			
		||||
import com.massivecraft.massivecore.cmd.req.ReqHasPerm;
 | 
			
		||||
import com.massivecraft.massivecore.cmd.req.ReqIsPlayer;
 | 
			
		||||
@@ -43,68 +45,52 @@ public class CmdFactionsClaim extends FactionsCommand
 | 
			
		||||
		Integer radius = this.arg(0, ARInteger.get(), 1);
 | 
			
		||||
		if (radius == null) return;
 | 
			
		||||
		
 | 
			
		||||
		final Faction forFaction = this.arg(1, ARFaction.get(), msenderFaction);
 | 
			
		||||
		if (forFaction == null) return;
 | 
			
		||||
		final Faction newFaction = this.arg(1, ARFaction.get(), msenderFaction);
 | 
			
		||||
		if (newFaction == null) return;
 | 
			
		||||
		
 | 
			
		||||
		// MPerm
 | 
			
		||||
		if (forFaction.isNormal() && !MPerm.getPermTerritory().has(msender, forFaction, true)) return;
 | 
			
		||||
		if (newFaction.isNormal() && ! MPerm.getPermTerritory().has(msender, newFaction, true)) return;
 | 
			
		||||
		
 | 
			
		||||
		// Validate
 | 
			
		||||
		// Radius Claim Min
 | 
			
		||||
		if (radius < 1)
 | 
			
		||||
		{
 | 
			
		||||
			msg("<b>If you specify a radius, it must be at least 1.");
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		if (radius > MConf.get().radiusClaimRadiusLimit && !msender.isUsingAdminMode())
 | 
			
		||||
		// Radius Claim Perm
 | 
			
		||||
		if (radius > 1 && ! Perm.CLAIM_RADIUS.has(sender, false))
 | 
			
		||||
		{
 | 
			
		||||
			msg("<b>You do not have permission to claim in a radius.");
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		// Radius Claim Max
 | 
			
		||||
		if (radius > MConf.get().radiusClaimRadiusLimit && ! msender.isUsingAdminMode())
 | 
			
		||||
		{
 | 
			
		||||
			msg("<b>The maximum radius allowed is <h>%s<b>.", MConf.get().radiusClaimRadiusLimit);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		// Apply
 | 
			
		||||
		
 | 
			
		||||
		// single chunk
 | 
			
		||||
		if (radius < 2)
 | 
			
		||||
		// Get Chunks
 | 
			
		||||
		final int radiusZero = radius -1;
 | 
			
		||||
		final PS chunk = PS.valueOf(me).getChunk(true);
 | 
			
		||||
		final int xmin = chunk.getChunkX() - radiusZero;
 | 
			
		||||
		final int xmax = chunk.getChunkX() + radiusZero;
 | 
			
		||||
		final int zmin = chunk.getChunkZ() - radiusZero;
 | 
			
		||||
		final int zmax = chunk.getChunkZ() + radiusZero;
 | 
			
		||||
		Set<PS> chunks = new LinkedHashSet<PS>();
 | 
			
		||||
		chunks.add(chunk); // The center should come first for pretty messages
 | 
			
		||||
		for (int x = xmin; x <= xmax; x++)
 | 
			
		||||
		{
 | 
			
		||||
			msender.tryClaim(forFaction, PS.valueOf(me), true, true);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		// radius claim
 | 
			
		||||
		if (!Perm.CLAIM_RADIUS.has(sender, false))
 | 
			
		||||
		{
 | 
			
		||||
			msg("<b>You do not have permission to claim in a radius.");
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// TODO: There must be a better way than using a spiral task.
 | 
			
		||||
		// TODO: Do some research to allow for claming sets of chunks in a batch with atomicity.
 | 
			
		||||
		// This will probably result in an alteration to the owner change event.
 | 
			
		||||
		// It would possibly contain a set of chunks instead of a single chunk.
 | 
			
		||||
		
 | 
			
		||||
		new SpiralTask(PS.valueOf(me), radius)
 | 
			
		||||
		{
 | 
			
		||||
			private int failCount = 0;
 | 
			
		||||
			private final int limit = MConf.get().radiusClaimFailureLimit - 1;
 | 
			
		||||
 | 
			
		||||
			@Override
 | 
			
		||||
			public boolean work()
 | 
			
		||||
			for (int z = zmin; z <= zmax; z++)
 | 
			
		||||
			{
 | 
			
		||||
				boolean success = msender.tryClaim(forFaction, PS.valueOf(this.currentLocation()), true, true);
 | 
			
		||||
				if (success)
 | 
			
		||||
				{
 | 
			
		||||
					this.failCount = 0;
 | 
			
		||||
				}
 | 
			
		||||
				else if (this.failCount++ >= this.limit)
 | 
			
		||||
				{
 | 
			
		||||
					this.stop();
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
				return true;
 | 
			
		||||
				chunks.add(chunk.withChunkX(x).withChunkZ(z));
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		// Apply / Inform
 | 
			
		||||
		msender.tryClaim(newFaction, chunks);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,7 @@
 | 
			
		||||
package com.massivecraft.factions.cmd;
 | 
			
		||||
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
 | 
			
		||||
import com.massivecraft.factions.cmd.req.ReqHasFaction;
 | 
			
		||||
import com.massivecraft.factions.entity.Faction;
 | 
			
		||||
import com.massivecraft.factions.entity.FactionColl;
 | 
			
		||||
@@ -37,7 +39,7 @@ public class CmdFactionsUnclaim extends FactionsCommand
 | 
			
		||||
		Faction newFaction = FactionColl.get().getNone();
 | 
			
		||||
 | 
			
		||||
		// Apply
 | 
			
		||||
		if (msender.tryClaim(newFaction, chunk, true, true)) return;
 | 
			
		||||
		if (msender.tryClaim(newFaction, Collections.singletonList(chunk))) return;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,6 @@ package com.massivecraft.factions.cmd;
 | 
			
		||||
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import com.massivecraft.factions.Factions;
 | 
			
		||||
import com.massivecraft.factions.Perm;
 | 
			
		||||
import com.massivecraft.factions.Rel;
 | 
			
		||||
import com.massivecraft.factions.cmd.req.ReqHasFaction;
 | 
			
		||||
@@ -10,9 +9,7 @@ import com.massivecraft.factions.cmd.req.ReqRoleIsAtLeast;
 | 
			
		||||
import com.massivecraft.factions.entity.BoardColl;
 | 
			
		||||
import com.massivecraft.factions.entity.Faction;
 | 
			
		||||
import com.massivecraft.factions.entity.FactionColl;
 | 
			
		||||
import com.massivecraft.factions.entity.MConf;
 | 
			
		||||
import com.massivecraft.factions.entity.MPerm;
 | 
			
		||||
import com.massivecraft.factions.event.EventFactionsChunkChange;
 | 
			
		||||
import com.massivecraft.massivecore.cmd.req.ReqHasPerm;
 | 
			
		||||
import com.massivecraft.massivecore.ps.PS;
 | 
			
		||||
 | 
			
		||||
@@ -49,12 +46,15 @@ public class CmdFactionsUnclaimall extends FactionsCommand
 | 
			
		||||
 | 
			
		||||
		// Apply
 | 
			
		||||
		Set<PS> chunks = BoardColl.get().getChunks(faction);
 | 
			
		||||
		msender.tryClaim(newFaction, chunks);
 | 
			
		||||
		
 | 
			
		||||
		/*
 | 
			
		||||
		int countTotal = chunks.size();
 | 
			
		||||
		int countSuccess = 0;
 | 
			
		||||
		int countFail = 0;
 | 
			
		||||
		for (PS chunk : chunks)
 | 
			
		||||
		{
 | 
			
		||||
			EventFactionsChunkChange event = new EventFactionsChunkChange(sender, chunk, newFaction);
 | 
			
		||||
			EventFactionsChunksChange event = new EventFactionsChunksChange(sender, chunk, newFaction);
 | 
			
		||||
			event.run();
 | 
			
		||||
			if (event.isCancelled())
 | 
			
		||||
			{
 | 
			
		||||
@@ -74,7 +74,8 @@ public class CmdFactionsUnclaimall extends FactionsCommand
 | 
			
		||||
		if (MConf.get().logLandUnclaims)
 | 
			
		||||
		{
 | 
			
		||||
			Factions.get().log(msender.getName()+" unclaimed everything for the faction: "+msenderFaction.getName());
 | 
			
		||||
		}
 | 
			
		||||
		}*/
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,10 @@
 | 
			
		||||
package com.massivecraft.factions.engine;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map.Entry;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import org.bukkit.event.EventHandler;
 | 
			
		||||
import org.bukkit.event.EventPriority;
 | 
			
		||||
import org.bukkit.plugin.Plugin;
 | 
			
		||||
@@ -9,7 +14,7 @@ import com.massivecraft.factions.entity.Faction;
 | 
			
		||||
import com.massivecraft.factions.entity.MConf;
 | 
			
		||||
import com.massivecraft.factions.entity.MPlayer;
 | 
			
		||||
import com.massivecraft.factions.event.EventFactionsAbstractSender;
 | 
			
		||||
import com.massivecraft.factions.event.EventFactionsChunkChange;
 | 
			
		||||
import com.massivecraft.factions.event.EventFactionsChunksChange;
 | 
			
		||||
import com.massivecraft.factions.event.EventFactionsChunkChangeType;
 | 
			
		||||
import com.massivecraft.factions.event.EventFactionsCreate;
 | 
			
		||||
import com.massivecraft.factions.event.EventFactionsDescriptionChange;
 | 
			
		||||
@@ -26,6 +31,8 @@ import com.massivecraft.factions.event.EventFactionsTitleChange;
 | 
			
		||||
import com.massivecraft.factions.integration.Econ;
 | 
			
		||||
import com.massivecraft.massivecore.EngineAbstract;
 | 
			
		||||
import com.massivecraft.massivecore.money.Money;
 | 
			
		||||
import com.massivecraft.massivecore.ps.PS;
 | 
			
		||||
import com.massivecraft.massivecore.util.Txt;
 | 
			
		||||
 | 
			
		||||
public class EngineEcon extends EngineAbstract
 | 
			
		||||
{
 | 
			
		||||
@@ -116,13 +123,27 @@ public class EngineEcon extends EngineAbstract
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
 | 
			
		||||
	public void payForAction(EventFactionsChunkChange event)
 | 
			
		||||
	public void payForAction(EventFactionsChunksChange event)
 | 
			
		||||
	{
 | 
			
		||||
		EventFactionsChunkChangeType type = event.getType();
 | 
			
		||||
		Double cost = MConf.get().econChunkCost.get(type);
 | 
			
		||||
		double cost = 0;
 | 
			
		||||
		List<String> typeNames = new ArrayList<String>();
 | 
			
		||||
		
 | 
			
		||||
		String desc = type.toString().toLowerCase() + " this land";
 | 
			
		||||
		for (Entry<EventFactionsChunkChangeType, Set<PS>> typeChunks : event.getTypeChunks().entrySet())
 | 
			
		||||
		{
 | 
			
		||||
			final EventFactionsChunkChangeType type = typeChunks.getKey();
 | 
			
		||||
			final Set<PS> chunks = typeChunks.getValue();
 | 
			
		||||
			
 | 
			
		||||
			Double typeCost = MConf.get().econChunkCost.get(type);
 | 
			
		||||
			if (typeCost == null) continue;
 | 
			
		||||
			if (typeCost == 0) continue;
 | 
			
		||||
			
 | 
			
		||||
			typeCost *= chunks.size();
 | 
			
		||||
			cost += typeCost;
 | 
			
		||||
			
 | 
			
		||||
			typeNames.add(type.now);
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		String desc = Txt.implodeCommaAnd(typeNames) + " this land";
 | 
			
		||||
		payForAction(event, cost, desc);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
 
 | 
			
		||||
@@ -2,10 +2,12 @@ package com.massivecraft.factions.engine;
 | 
			
		||||
 | 
			
		||||
import java.text.MessageFormat;
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Iterator;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import org.bukkit.Bukkit;
 | 
			
		||||
import org.bukkit.Location;
 | 
			
		||||
@@ -62,12 +64,14 @@ import com.massivecraft.factions.Factions;
 | 
			
		||||
import com.massivecraft.factions.Rel;
 | 
			
		||||
import com.massivecraft.factions.TerritoryAccess;
 | 
			
		||||
import com.massivecraft.factions.entity.BoardColl;
 | 
			
		||||
import com.massivecraft.factions.entity.FactionColl;
 | 
			
		||||
import com.massivecraft.factions.entity.MFlag;
 | 
			
		||||
import com.massivecraft.factions.entity.MPerm;
 | 
			
		||||
import com.massivecraft.factions.entity.MPlayer;
 | 
			
		||||
import com.massivecraft.factions.entity.Faction;
 | 
			
		||||
import com.massivecraft.factions.entity.MConf;
 | 
			
		||||
import com.massivecraft.factions.entity.MPlayerColl;
 | 
			
		||||
import com.massivecraft.factions.event.EventFactionsChunksChange;
 | 
			
		||||
import com.massivecraft.factions.event.EventFactionsPvpDisallowed;
 | 
			
		||||
import com.massivecraft.factions.event.EventFactionsPowerChange;
 | 
			
		||||
import com.massivecraft.factions.event.EventFactionsPowerChange.PowerChangeReason;
 | 
			
		||||
@@ -230,6 +234,167 @@ public class EngineMain extends EngineAbstract
 | 
			
		||||
	// CHUNK CHANGE: DETECT
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	
 | 
			
		||||
	@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
 | 
			
		||||
	public void onChunksChange(EventFactionsChunksChange event)
 | 
			
		||||
	{
 | 
			
		||||
		// Args
 | 
			
		||||
		final MPlayer msender = event.getMSender();
 | 
			
		||||
		final Faction newFaction = event.getNewFaction();
 | 
			
		||||
		final Map<Faction, Set<PS>> currentFactionChunks = event.getOldFactionChunks();
 | 
			
		||||
		final Set<Faction> currentFactions = currentFactionChunks.keySet();
 | 
			
		||||
		final Set<PS> chunks = event.getChunks();
 | 
			
		||||
		
 | 
			
		||||
		// Admin Mode? Sure!
 | 
			
		||||
		if (msender.isUsingAdminMode()) return;
 | 
			
		||||
		
 | 
			
		||||
		// CALC: Is there at least one normal faction among the current ones?
 | 
			
		||||
		boolean currentFactionsContainsAtLeastOneNormal = false;
 | 
			
		||||
		for (Faction currentFaction : currentFactions)
 | 
			
		||||
		{
 | 
			
		||||
			if (currentFaction.isNormal())
 | 
			
		||||
			{
 | 
			
		||||
				currentFactionsContainsAtLeastOneNormal = true;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		// If the new faction is normal (not wilderness/none), meaning if we are claiming for a faction ...
 | 
			
		||||
		if (newFaction.isNormal())
 | 
			
		||||
		{
 | 
			
		||||
			// ... ensure claiming is enabled for the worlds of all chunks ...
 | 
			
		||||
			for (PS chunk : chunks)
 | 
			
		||||
			{
 | 
			
		||||
				String worldId = chunk.getWorld();
 | 
			
		||||
				if ( ! MConf.get().worldsClaimingEnabled.contains(worldId))
 | 
			
		||||
				{
 | 
			
		||||
					String worldName = Mixin.getWorldDisplayName(worldId);
 | 
			
		||||
					msender.msg("<b>Land claiming is disabled in <h>%s<b>.", worldName);
 | 
			
		||||
					event.setCancelled(true);
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			// ... ensure we have permission to alter the territory of the new faction ...
 | 
			
		||||
			if ( ! MPerm.getPermTerritory().has(msender, newFaction, true))
 | 
			
		||||
			{
 | 
			
		||||
				// NOTE: No need to send a message. We send message from the permission check itself.
 | 
			
		||||
				event.setCancelled(true);
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			// ... ensure the new faction has enough players to claim ...
 | 
			
		||||
			if (newFaction.getMPlayers().size() < MConf.get().claimsRequireMinFactionMembers)
 | 
			
		||||
			{
 | 
			
		||||
				msender.msg("<b>Factions must have at least <h>%s<b> members to claim land.", MConf.get().claimsRequireMinFactionMembers);
 | 
			
		||||
				event.setCancelled(true);
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			// ... ensure the claim would not bypass the global max limit ...
 | 
			
		||||
			int ownedLand = newFaction.getLandCount();
 | 
			
		||||
			if (MConf.get().claimedLandsMax != 0 && ownedLand + chunks.size() > MConf.get().claimedLandsMax && ! newFaction.getFlag(MFlag.getFlagInfpower()))
 | 
			
		||||
			{
 | 
			
		||||
				msender.msg("<b>Limit reached. You can't claim more land.");
 | 
			
		||||
				event.setCancelled(true);
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			// ... ensure the claim would not bypass the faction power ...
 | 
			
		||||
			if (ownedLand + chunks.size() > newFaction.getPowerRounded())
 | 
			
		||||
			{
 | 
			
		||||
				msender.msg("<b>You don't have enough power to claim that land.");
 | 
			
		||||
				event.setCancelled(true);
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			// ... ensure the claim would not violate distance to neighbors ...
 | 
			
		||||
			// HOW: Calculate the factions nearby, excluding the chunks themselves, the faction itself and the wilderness faction.
 | 
			
		||||
			// HOW: The chunks themselves will be handled in the "if (oldFaction.isNormal())" section below. 
 | 
			
		||||
			Set<PS> nearbyChunks = BoardColl.getNearbyChunks(chunks, MConf.get().claimMinimumChunksDistanceToOthers);
 | 
			
		||||
			nearbyChunks.removeAll(chunks);
 | 
			
		||||
			Set<Faction> nearbyFactions = BoardColl.getDistinctFactions(nearbyChunks);
 | 
			
		||||
			nearbyFactions.remove(FactionColl.get().getNone());
 | 
			
		||||
			nearbyFactions.remove(newFaction);
 | 
			
		||||
			// HOW: Next we check if the new faction has permission to claim nearby the nearby factions.
 | 
			
		||||
			MPerm claimnear = MPerm.getPermClaimnear();
 | 
			
		||||
			for (Faction nearbyFaction : nearbyFactions)
 | 
			
		||||
			{
 | 
			
		||||
				if (claimnear.has(newFaction, nearbyFaction)) continue;
 | 
			
		||||
				msender.sendMessage(claimnear.createDeniedMessage(msender, nearbyFaction));
 | 
			
		||||
				event.setCancelled(true);
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			// ... ensure claims are properly connected ...
 | 
			
		||||
			if
 | 
			
		||||
			(
 | 
			
		||||
				// If claims must be connected ...
 | 
			
		||||
				MConf.get().claimsMustBeConnected
 | 
			
		||||
				// ... and this faction already has claimed something on this map (meaning it's not their first claim) ... 
 | 
			
		||||
				&&
 | 
			
		||||
				newFaction.getLandCountInWorld(chunks.iterator().next().getWorld()) > 0
 | 
			
		||||
				// ... and none of the chunks are connected to an already claimed chunk for the faction ...
 | 
			
		||||
				&&
 | 
			
		||||
				! BoardColl.get().isAnyConnectedPs(chunks, newFaction)
 | 
			
		||||
				// ... and either claims must always be connected or there is at least one normal faction among the old factions ...
 | 
			
		||||
				&&
 | 
			
		||||
				( ! MConf.get().claimsCanBeUnconnectedIfOwnedByOtherFaction || currentFactionsContainsAtLeastOneNormal)
 | 
			
		||||
			)
 | 
			
		||||
			{
 | 
			
		||||
				if (MConf.get().claimsCanBeUnconnectedIfOwnedByOtherFaction)
 | 
			
		||||
				{
 | 
			
		||||
					msender.msg("<b>You can only claim additional land which is connected to your first claim or controlled by another faction!");
 | 
			
		||||
				}
 | 
			
		||||
				else
 | 
			
		||||
				{
 | 
			
		||||
					msender.msg("<b>You can only claim additional land which is connected to your first claim!");
 | 
			
		||||
				}
 | 
			
		||||
				event.setCancelled(true);
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		// For each of the old factions ...
 | 
			
		||||
		for (Faction oldFaction : currentFactions)
 | 
			
		||||
		{
 | 
			
		||||
			// ... that is an actual faction ...
 | 
			
		||||
			if (oldFaction.isNone()) continue;
 | 
			
		||||
			
 | 
			
		||||
			// ... for which the msender lacks permission ...
 | 
			
		||||
			if (MPerm.getPermTerritory().has(msender, oldFaction, false)) continue;
 | 
			
		||||
			
 | 
			
		||||
			// ... print the error message of choice ...
 | 
			
		||||
			if (msender.hasFaction() && msender.getFaction() == oldFaction)
 | 
			
		||||
			{
 | 
			
		||||
				msender.sendMessage(MPerm.getPermTerritory().createDeniedMessage(msender, oldFaction));
 | 
			
		||||
			}
 | 
			
		||||
			else if ( ! MConf.get().claimingFromOthersAllowed)
 | 
			
		||||
			{
 | 
			
		||||
				msender.msg("<b>You may not claim land from others.");
 | 
			
		||||
			}
 | 
			
		||||
			else if (oldFaction.getRelationTo(newFaction).isAtLeast(Rel.TRUCE))
 | 
			
		||||
			{
 | 
			
		||||
				msender.msg("<b>You can't claim this land due to your relation with the current owner.");
 | 
			
		||||
			}
 | 
			
		||||
			else if ( ! oldFaction.hasLandInflation())
 | 
			
		||||
			{
 | 
			
		||||
				msender.msg("%s<i> owns this land and is strong enough to keep it.", oldFaction.getName(msender));
 | 
			
		||||
			}
 | 
			
		||||
			else if ( ! BoardColl.get().isAnyBorderPs(chunks))
 | 
			
		||||
			{
 | 
			
		||||
				msender.msg("<b>You must start claiming land at the border of the territory.");
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			// ... and cancel.
 | 
			
		||||
			event.setCancelled(true);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// CHUNK CHANGE: DETECT
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	
 | 
			
		||||
	@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
 | 
			
		||||
	public void chunkChangeDetect(PlayerMoveEvent event)
 | 
			
		||||
	{
 | 
			
		||||
@@ -307,7 +472,7 @@ public class EngineMain extends EngineAbstract
 | 
			
		||||
		if (autoClaimFaction == null) return;
 | 
			
		||||
		
 | 
			
		||||
		// ... try claim.
 | 
			
		||||
		mplayer.tryClaim(autoClaimFaction, chunkTo, true, true);
 | 
			
		||||
		mplayer.tryClaim(autoClaimFaction, Collections.singletonList(chunkTo));
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
 
 | 
			
		||||
@@ -242,6 +242,16 @@ public class Board extends Entity<Board> implements BoardInterface
 | 
			
		||||
		
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean isAnyBorderPs(Set<PS> pss)
 | 
			
		||||
	{
 | 
			
		||||
		for (PS ps : pss)
 | 
			
		||||
		{
 | 
			
		||||
			if (this.isBorderPs(ps)) return true;
 | 
			
		||||
		}
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Is this coord connected to any coord claimed by the specified faction?
 | 
			
		||||
	@Override
 | 
			
		||||
@@ -266,6 +276,16 @@ public class Board extends Entity<Board> implements BoardInterface
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean isAnyConnectedPs(Set<PS> pss, Faction faction)
 | 
			
		||||
	{
 | 
			
		||||
		for (PS ps : pss)
 | 
			
		||||
		{
 | 
			
		||||
			if (this.isConnectedPs(ps, faction)) return true;
 | 
			
		||||
		}
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// MAP GENERATION
 | 
			
		||||
	
 | 
			
		||||
	@Override
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,9 @@ package com.massivecraft.factions.entity;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.LinkedHashMap;
 | 
			
		||||
import java.util.LinkedHashSet;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import com.massivecraft.factions.Const;
 | 
			
		||||
@@ -150,6 +152,16 @@ public class BoardColl extends Coll<Board> implements BoardInterface
 | 
			
		||||
		return board.isBorderPs(ps);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean isAnyBorderPs(Set<PS> pss)
 | 
			
		||||
	{
 | 
			
		||||
		for (PS ps : pss)
 | 
			
		||||
		{
 | 
			
		||||
			if (this.isBorderPs(ps)) return true;
 | 
			
		||||
		}
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean isConnectedPs(PS ps, Faction faction)
 | 
			
		||||
	{
 | 
			
		||||
@@ -159,6 +171,16 @@ public class BoardColl extends Coll<Board> implements BoardInterface
 | 
			
		||||
		return board.isConnectedPs(ps, faction);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean isAnyConnectedPs(Set<PS> pss, Faction faction)
 | 
			
		||||
	{
 | 
			
		||||
		for (PS ps : pss)
 | 
			
		||||
		{
 | 
			
		||||
			if (this.isConnectedPs(ps, faction)) return true;
 | 
			
		||||
		}
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// MAP GENERATION
 | 
			
		||||
	
 | 
			
		||||
	@Override
 | 
			
		||||
@@ -177,7 +199,7 @@ public class BoardColl extends Coll<Board> implements BoardInterface
 | 
			
		||||
	// Distance -1 returns 0 chunks always.
 | 
			
		||||
	// Distance 0 returns 1 chunk only (the one supplied).
 | 
			
		||||
	// Distance 1 returns 3x3 = 9 chunks.
 | 
			
		||||
	public static Set<PS> getNearbyChunks(PS chunk, int distance, boolean includeSelf)
 | 
			
		||||
	public static Set<PS> getNearbyChunks(PS chunk, int distance)
 | 
			
		||||
	{
 | 
			
		||||
		// Fix Args
 | 
			
		||||
		if (chunk == null) throw new NullPointerException("chunk");
 | 
			
		||||
@@ -187,7 +209,6 @@ public class BoardColl extends Coll<Board> implements BoardInterface
 | 
			
		||||
		Set<PS> ret = new LinkedHashSet<PS>();
 | 
			
		||||
		
 | 
			
		||||
		if (distance < 0) return ret;
 | 
			
		||||
		// if (distance == 0 && ! includeSelf) return ret; // This will be done by the code below.
 | 
			
		||||
		
 | 
			
		||||
		// Main
 | 
			
		||||
		int xmin = chunk.getChunkX() - distance;
 | 
			
		||||
@@ -200,7 +221,6 @@ public class BoardColl extends Coll<Board> implements BoardInterface
 | 
			
		||||
		{
 | 
			
		||||
			for (int z = zmin; z <= zmax; z++)
 | 
			
		||||
			{
 | 
			
		||||
				if ( ! includeSelf && x == chunk.getChunkX() && z == chunk.getChunkZ()) continue;
 | 
			
		||||
				ret.add(chunk.withChunkX(x).withChunkZ(z));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@@ -209,6 +229,26 @@ public class BoardColl extends Coll<Board> implements BoardInterface
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public static Set<PS> getNearbyChunks(Collection<PS> chunks, int distance)
 | 
			
		||||
	{
 | 
			
		||||
		// Fix Args
 | 
			
		||||
		if (chunks == null) throw new NullPointerException("chunks");
 | 
			
		||||
		
 | 
			
		||||
		// Create Ret
 | 
			
		||||
		Set<PS> ret = new LinkedHashSet<PS>();
 | 
			
		||||
		
 | 
			
		||||
		if (distance < 0) return ret;
 | 
			
		||||
		
 | 
			
		||||
		// Main
 | 
			
		||||
		for (PS chunk : chunks)
 | 
			
		||||
		{
 | 
			
		||||
			ret.addAll(getNearbyChunks(chunk, distance));
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		// Return Ret
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public static Set<Faction> getDistinctFactions(Collection<PS> chunks)
 | 
			
		||||
	{
 | 
			
		||||
		// Fix Args
 | 
			
		||||
@@ -229,4 +269,19 @@ public class BoardColl extends Coll<Board> implements BoardInterface
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public static Map<PS, Faction> getChunkFaction(Collection<PS> chunks)
 | 
			
		||||
	{
 | 
			
		||||
		Map<PS, Faction> ret = new LinkedHashMap<PS, Faction>();
 | 
			
		||||
		
 | 
			
		||||
		for (PS chunk : chunks)
 | 
			
		||||
		{
 | 
			
		||||
			chunk = chunk.getChunk(true);
 | 
			
		||||
			Faction faction = get().getFactionAt(chunk);
 | 
			
		||||
			if (faction == null) faction = FactionColl.get().getNone();
 | 
			
		||||
			ret.put(chunk, faction);
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -30,7 +30,9 @@ public interface BoardInterface
 | 
			
		||||
	
 | 
			
		||||
	// NEARBY DETECTION
 | 
			
		||||
	public boolean isBorderPs(PS ps);
 | 
			
		||||
	public boolean isAnyBorderPs(Set<PS> pss);
 | 
			
		||||
	public boolean isConnectedPs(PS ps, Faction faction);
 | 
			
		||||
	public boolean isAnyConnectedPs(Set<PS> pss, Faction faction);
 | 
			
		||||
	
 | 
			
		||||
	// MAP
 | 
			
		||||
	// TODO: Could the degrees be embedded in centerPs yaw instead?
 | 
			
		||||
 
 | 
			
		||||
@@ -151,9 +151,6 @@ public class MConf extends Entity<MConf>
 | 
			
		||||
	// CLAIM LIMITS
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	
 | 
			
		||||
	// if someone is doing a radius claim and the process fails to claim land this many times in a row, it will exit
 | 
			
		||||
	public int radiusClaimFailureLimit = 9;
 | 
			
		||||
	
 | 
			
		||||
	// the maximum radius allowed when using the claim command.
 | 
			
		||||
	public int radiusClaimRadiusLimit = 5;
 | 
			
		||||
	
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,9 @@
 | 
			
		||||
package com.massivecraft.factions.entity;
 | 
			
		||||
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.Iterator;
 | 
			
		||||
import java.util.Map.Entry;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import org.bukkit.ChatColor;
 | 
			
		||||
@@ -12,7 +15,8 @@ import com.massivecraft.factions.Lang;
 | 
			
		||||
import com.massivecraft.factions.Perm;
 | 
			
		||||
import com.massivecraft.factions.Rel;
 | 
			
		||||
import com.massivecraft.factions.RelationParticipator;
 | 
			
		||||
import com.massivecraft.factions.event.EventFactionsChunkChange;
 | 
			
		||||
import com.massivecraft.factions.event.EventFactionsChunkChangeType;
 | 
			
		||||
import com.massivecraft.factions.event.EventFactionsChunksChange;
 | 
			
		||||
import com.massivecraft.factions.event.EventFactionsMembershipChange;
 | 
			
		||||
import com.massivecraft.factions.event.EventFactionsRemovePlayerMillis;
 | 
			
		||||
import com.massivecraft.factions.event.EventFactionsMembershipChange.MembershipChangeReason;
 | 
			
		||||
@@ -793,163 +797,91 @@ public class MPlayer extends SenderEntity<MPlayer> implements EconomyParticipato
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public boolean tryClaim(Faction newFaction, PS ps, boolean verbooseChange, boolean verbooseSame)
 | 
			
		||||
	// NEW
 | 
			
		||||
	public boolean tryClaim(Faction newFaction, Collection<PS> pss)
 | 
			
		||||
	{
 | 
			
		||||
		PS chunk = ps.getChunk(true);
 | 
			
		||||
		Faction oldFaction = BoardColl.get().getFactionAt(chunk);
 | 
			
		||||
		// Args
 | 
			
		||||
		if (newFaction == null) throw new NullPointerException("newFaction");
 | 
			
		||||
		
 | 
			
		||||
		MConf mconf = MConf.get();
 | 
			
		||||
		if (pss == null) throw new NullPointerException("pss");
 | 
			
		||||
		final Set<PS> chunks = PS.getDistinctChunks(pss);
 | 
			
		||||
		
 | 
			
		||||
		// NoChange
 | 
			
		||||
		if (newFaction == oldFaction)
 | 
			
		||||
		// We clean the chunks further by removing what does not change.
 | 
			
		||||
		// This is also very suggested cleaning of EventFactionsChunksChange input. 
 | 
			
		||||
		Iterator<PS> iter = chunks.iterator();
 | 
			
		||||
		while (iter.hasNext())
 | 
			
		||||
		{
 | 
			
		||||
			PS chunk = iter.next();
 | 
			
		||||
			Faction oldFaction = BoardColl.get().getFactionAt(chunk);
 | 
			
		||||
			if (newFaction == oldFaction) iter.remove();
 | 
			
		||||
		}
 | 
			
		||||
		if (chunks.isEmpty())
 | 
			
		||||
		{
 | 
			
		||||
			msg("%s<i> already owns this land.", newFaction.describeTo(this, true));
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		if ( ! this.isUsingAdminMode())
 | 
			
		||||
		{
 | 
			
		||||
			if (newFaction.isNormal())
 | 
			
		||||
			{
 | 
			
		||||
				if ( ! mconf.worldsClaimingEnabled.contains(ps.getWorld()))
 | 
			
		||||
				{
 | 
			
		||||
					msg("<b>Sorry, this world has land claiming disabled.");
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
				
 | 
			
		||||
				if ( ! MPerm.getPermTerritory().has(this, newFaction, true))
 | 
			
		||||
				{
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
				
 | 
			
		||||
				if (newFaction.getMPlayers().size() < mconf.claimsRequireMinFactionMembers)
 | 
			
		||||
				{
 | 
			
		||||
					msg("Factions must have at least <h>%s<b> members to claim land.", mconf.claimsRequireMinFactionMembers);
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
				
 | 
			
		||||
				int ownedLand = newFaction.getLandCount();
 | 
			
		||||
				
 | 
			
		||||
				if (mconf.claimedLandsMax != 0 && ownedLand >= mconf.claimedLandsMax && ! newFaction.getFlag(MFlag.getFlagInfpower()))
 | 
			
		||||
				{
 | 
			
		||||
					msg("<b>Limit reached. You can't claim more land.");
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
				
 | 
			
		||||
				if (ownedLand >= newFaction.getPowerRounded())
 | 
			
		||||
				{
 | 
			
		||||
					msg("<b>You can't claim more land. You need more power.");
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
				
 | 
			
		||||
				// Calculate the factions nearby, excluding the chunk itself, the faction itself and the wilderness faction.
 | 
			
		||||
				// The chunk itself is handled in the "if (oldFaction.isNormal())" section below. 
 | 
			
		||||
				Set<PS> nearbyChunks = BoardColl.getNearbyChunks(chunk, MConf.get().claimMinimumChunksDistanceToOthers, false);
 | 
			
		||||
				Set<Faction> nearbyFactions = BoardColl.getDistinctFactions(nearbyChunks);
 | 
			
		||||
				nearbyFactions.remove(FactionColl.get().getNone());
 | 
			
		||||
				nearbyFactions.remove(newFaction);
 | 
			
		||||
				// Next we check if the new faction has permission to claim nearby the nearby factions.
 | 
			
		||||
				MPerm claimnear = MPerm.getPermClaimnear();
 | 
			
		||||
				for (Faction nearbyFaction : nearbyFactions)
 | 
			
		||||
				{
 | 
			
		||||
					if (claimnear.has(newFaction, nearbyFaction)) continue;
 | 
			
		||||
					sendMessage(claimnear.createDeniedMessage(this, nearbyFaction));
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
				
 | 
			
		||||
				if
 | 
			
		||||
				(
 | 
			
		||||
					mconf.claimsMustBeConnected
 | 
			
		||||
					&&
 | 
			
		||||
					newFaction.getLandCountInWorld(ps.getWorld()) > 0
 | 
			
		||||
					&&
 | 
			
		||||
					! BoardColl.get().isConnectedPs(chunk, newFaction)
 | 
			
		||||
					&&
 | 
			
		||||
					( ! mconf.claimsCanBeUnconnectedIfOwnedByOtherFaction || oldFaction.isNone())
 | 
			
		||||
				)
 | 
			
		||||
				{
 | 
			
		||||
					if (mconf.claimsCanBeUnconnectedIfOwnedByOtherFaction)
 | 
			
		||||
					{
 | 
			
		||||
						msg("<b>You can only claim additional land which is connected to your first claim or controlled by another faction!");
 | 
			
		||||
					}
 | 
			
		||||
					else
 | 
			
		||||
					{
 | 
			
		||||
						msg("<b>You can only claim additional land which is connected to your first claim!");
 | 
			
		||||
					}
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			if (oldFaction.isNormal())
 | 
			
		||||
			{
 | 
			
		||||
				if ( ! MPerm.getPermTerritory().has(this, oldFaction, false))
 | 
			
		||||
				{
 | 
			
		||||
					if (this.hasFaction() && this.getFaction() == oldFaction)
 | 
			
		||||
					{
 | 
			
		||||
						sendMessage(MPerm.getPermTerritory().createDeniedMessage(this, oldFaction));
 | 
			
		||||
						return false;
 | 
			
		||||
					}
 | 
			
		||||
					
 | 
			
		||||
					if ( ! mconf.claimingFromOthersAllowed)
 | 
			
		||||
					{
 | 
			
		||||
						msg("<b>You may not claim land from others.");
 | 
			
		||||
						return false;
 | 
			
		||||
					}
 | 
			
		||||
					
 | 
			
		||||
					if (oldFaction.getRelationTo(newFaction).isAtLeast(Rel.TRUCE))
 | 
			
		||||
					{
 | 
			
		||||
						msg("<b>You can't claim this land due to your relation with the current owner.");
 | 
			
		||||
						return false;
 | 
			
		||||
					}
 | 
			
		||||
					
 | 
			
		||||
					if ( ! oldFaction.hasLandInflation())
 | 
			
		||||
					{
 | 
			
		||||
						msg("%s<i> owns this land and is strong enough to keep it.", oldFaction.getName(this));
 | 
			
		||||
						return false;
 | 
			
		||||
					}
 | 
			
		||||
					
 | 
			
		||||
					if ( ! BoardColl.get().isBorderPs(chunk))
 | 
			
		||||
					{
 | 
			
		||||
						msg("<b>You must start claiming land at the border of the territory.");
 | 
			
		||||
						return false;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		// Event
 | 
			
		||||
		EventFactionsChunkChange event = new EventFactionsChunkChange(this.getSender(), chunk, newFaction);
 | 
			
		||||
		// NOTE: We listen to this event ourselves at LOW.
 | 
			
		||||
		// NOTE: That is where we apply the standard checks.
 | 
			
		||||
		EventFactionsChunksChange event = new EventFactionsChunksChange(this.getSender(), chunks, newFaction);
 | 
			
		||||
		event.run();
 | 
			
		||||
		if (event.isCancelled()) return false;
 | 
			
		||||
 | 
			
		||||
		
 | 
			
		||||
		// Apply
 | 
			
		||||
		BoardColl.get().setFactionAt(chunk, newFaction);
 | 
			
		||||
		for (PS chunk : chunks)
 | 
			
		||||
		{
 | 
			
		||||
			BoardColl.get().setFactionAt(chunk, newFaction);
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		// Inform
 | 
			
		||||
		Set<MPlayer> informees = new HashSet<MPlayer>();
 | 
			
		||||
		informees.add(this);
 | 
			
		||||
		if (newFaction.isNormal())
 | 
			
		||||
		for (Entry<Faction, Set<PS>> entry : event.getOldFactionChunks().entrySet())
 | 
			
		||||
		{
 | 
			
		||||
			informees.addAll(newFaction.getMPlayers());
 | 
			
		||||
		}
 | 
			
		||||
		if (oldFaction.isNormal())
 | 
			
		||||
		{
 | 
			
		||||
			informees.addAll(oldFaction.getMPlayers());
 | 
			
		||||
		}
 | 
			
		||||
		if (MConf.get().logLandClaims)
 | 
			
		||||
		{
 | 
			
		||||
			informees.add(MPlayer.get(IdUtil.getConsole()));
 | 
			
		||||
			final Faction oldFaction = entry.getKey();
 | 
			
		||||
			final Set<PS> oldChunks = entry.getValue();
 | 
			
		||||
			final PS oldChunk = oldChunks.iterator().next();
 | 
			
		||||
			final Set<MPlayer> informees = getClaimInformees(this, oldFaction, newFaction);
 | 
			
		||||
			final EventFactionsChunkChangeType type = EventFactionsChunkChangeType.get(oldFaction, newFaction, this.getFaction());
 | 
			
		||||
			
 | 
			
		||||
			String chunkString = oldChunk.toString(PSFormatHumanSpace.get());
 | 
			
		||||
			String typeString = type.past;
 | 
			
		||||
			
 | 
			
		||||
			for (MPlayer informee : informees)
 | 
			
		||||
			{
 | 
			
		||||
				informee.msg("<h>%s<i> %s <h>%d <i>" + (oldChunks.size() == 1 ? "chunk" : "chunks") + " near %s", this.describeTo(informee, true), typeString, oldChunks.size(), chunkString);
 | 
			
		||||
				informee.msg("  <h>%s<i> --> <h>%s", oldFaction.describeTo(informee, true), newFaction.describeTo(informee, true));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		String chunkString = chunk.toString(PSFormatHumanSpace.get());
 | 
			
		||||
		String typeString = event.getType().past;
 | 
			
		||||
		for (MPlayer informee : informees)
 | 
			
		||||
		{
 | 
			
		||||
			informee.msg("<h>%s<i> %s %s <i>| <h>%s<i> --> <h>%s", this.describeTo(informee, true), typeString, chunkString, oldFaction.describeTo(informee, true), newFaction.describeTo(informee, true));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Success
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// UTIL
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	
 | 
			
		||||
	public static Set<MPlayer> getClaimInformees(MPlayer msender, Faction... factions)
 | 
			
		||||
	{
 | 
			
		||||
		Set<MPlayer> ret = new HashSet<MPlayer>();
 | 
			
		||||
		
 | 
			
		||||
		ret.add(msender);
 | 
			
		||||
		
 | 
			
		||||
		for (Faction faction : factions)
 | 
			
		||||
		{
 | 
			
		||||
			if (faction.isNormal())
 | 
			
		||||
			{
 | 
			
		||||
				ret.addAll(faction.getMPlayers());
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		if (MConf.get().logLandClaims)
 | 
			
		||||
		{
 | 
			
		||||
			ret.add(MPlayer.get(IdUtil.getConsole()));
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,59 +0,0 @@
 | 
			
		||||
package com.massivecraft.factions.event;
 | 
			
		||||
 | 
			
		||||
import org.bukkit.command.CommandSender;
 | 
			
		||||
import org.bukkit.event.HandlerList;
 | 
			
		||||
 | 
			
		||||
import com.massivecraft.factions.entity.BoardColl;
 | 
			
		||||
import com.massivecraft.factions.entity.Faction;
 | 
			
		||||
import com.massivecraft.factions.entity.MPlayer;
 | 
			
		||||
import com.massivecraft.massivecore.ps.PS;
 | 
			
		||||
 | 
			
		||||
public class EventFactionsChunkChange extends EventFactionsAbstractSender
 | 
			
		||||
{	
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// REQUIRED EVENT CODE
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	
 | 
			
		||||
	private static final HandlerList handlers = new HandlerList();
 | 
			
		||||
	@Override public HandlerList getHandlers() { return handlers; }
 | 
			
		||||
	public static HandlerList getHandlerList() { return handlers; }
 | 
			
		||||
	
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// FIELDS
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	
 | 
			
		||||
	private final PS chunk;
 | 
			
		||||
	public PS getChunk() { return this.chunk; }
 | 
			
		||||
	
 | 
			
		||||
	private final Faction currentFaction;
 | 
			
		||||
	private final Faction newFaction;
 | 
			
		||||
	public Faction getNewFaction() { return this.newFaction; }
 | 
			
		||||
	
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// CONSTRUCT
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	
 | 
			
		||||
	public EventFactionsChunkChange(CommandSender sender, PS chunk, Faction newFaction)
 | 
			
		||||
	{
 | 
			
		||||
		super(sender);
 | 
			
		||||
		this.chunk = chunk.getChunk(true);
 | 
			
		||||
		this.currentFaction = BoardColl.get().getFactionAt(chunk);
 | 
			
		||||
		this.newFaction = newFaction;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// UTIL
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	
 | 
			
		||||
	public EventFactionsChunkChangeType getType()
 | 
			
		||||
	{
 | 
			
		||||
		if (currentFaction.isNone()) return EventFactionsChunkChangeType.BUY;
 | 
			
		||||
		if (newFaction.isNormal()) return EventFactionsChunkChangeType.CONQUER;
 | 
			
		||||
		
 | 
			
		||||
		MPlayer usender = this.getMSender();
 | 
			
		||||
		if (usender != null && usender.getFaction() == currentFaction) return EventFactionsChunkChangeType.SELL;
 | 
			
		||||
		
 | 
			
		||||
		return EventFactionsChunkChangeType.PILLAGE;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
@@ -1,11 +1,14 @@
 | 
			
		||||
package com.massivecraft.factions.event;
 | 
			
		||||
 | 
			
		||||
import com.massivecraft.factions.entity.Faction;
 | 
			
		||||
 | 
			
		||||
public enum EventFactionsChunkChangeType
 | 
			
		||||
{
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// ENUM
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	
 | 
			
		||||
	NONE("none", "none"),
 | 
			
		||||
	BUY("buy", "bought"),
 | 
			
		||||
	SELL("sell", "sold"),
 | 
			
		||||
	CONQUER("conquer", "conquered"),
 | 
			
		||||
@@ -31,4 +34,17 @@ public enum EventFactionsChunkChangeType
 | 
			
		||||
		this.past = past;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// UTIL
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	
 | 
			
		||||
	public static EventFactionsChunkChangeType get(Faction oldFaction, Faction newFaction, Faction self)
 | 
			
		||||
	{
 | 
			
		||||
		if (newFaction == oldFaction) return NONE;
 | 
			
		||||
		if (oldFaction.isNone()) return BUY;
 | 
			
		||||
		if (newFaction.isNormal()) return CONQUER;
 | 
			
		||||
		if (oldFaction == self) return SELL;
 | 
			
		||||
		return PILLAGE;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,78 @@
 | 
			
		||||
package com.massivecraft.factions.event;
 | 
			
		||||
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.LinkedHashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Map.Entry;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import org.bukkit.command.CommandSender;
 | 
			
		||||
import org.bukkit.event.HandlerList;
 | 
			
		||||
 | 
			
		||||
import com.massivecraft.factions.entity.BoardColl;
 | 
			
		||||
import com.massivecraft.factions.entity.Faction;
 | 
			
		||||
import com.massivecraft.factions.entity.MPlayer;
 | 
			
		||||
import com.massivecraft.massivecore.ps.PS;
 | 
			
		||||
import com.massivecraft.massivecore.util.MUtil;
 | 
			
		||||
 | 
			
		||||
public class EventFactionsChunksChange extends EventFactionsAbstractSender
 | 
			
		||||
{	
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// REQUIRED EVENT CODE
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	
 | 
			
		||||
	private static final HandlerList handlers = new HandlerList();
 | 
			
		||||
	@Override public HandlerList getHandlers() { return handlers; }
 | 
			
		||||
	public static HandlerList getHandlerList() { return handlers; }
 | 
			
		||||
	
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// FIELDS
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	
 | 
			
		||||
	private final Set<PS> chunks;
 | 
			
		||||
	public Set<PS> getChunks() { return this.chunks; }
 | 
			
		||||
	
 | 
			
		||||
	private final Faction newFaction;
 | 
			
		||||
	public Faction getNewFaction() { return this.newFaction; }
 | 
			
		||||
	
 | 
			
		||||
	private final Map<PS, Faction> oldChunkFaction;
 | 
			
		||||
	public Map<PS, Faction> getOldChunkFaction() { return this.oldChunkFaction; }
 | 
			
		||||
	
 | 
			
		||||
	private final Map<Faction, Set<PS>> oldFactionChunks;
 | 
			
		||||
	public Map<Faction, Set<PS>> getOldFactionChunks() { return this.oldFactionChunks; }
 | 
			
		||||
	
 | 
			
		||||
	private final Map<PS, EventFactionsChunkChangeType> chunkType;
 | 
			
		||||
	public Map<PS, EventFactionsChunkChangeType> getChunkType() { return this.chunkType; }
 | 
			
		||||
	
 | 
			
		||||
	private final Map<EventFactionsChunkChangeType, Set<PS>> typeChunks;
 | 
			
		||||
	public Map<EventFactionsChunkChangeType, Set<PS>> getTypeChunks() { return this.typeChunks; }
 | 
			
		||||
	
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// CONSTRUCT
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	
 | 
			
		||||
	public EventFactionsChunksChange(CommandSender sender, Set<PS> chunks, Faction newFaction)
 | 
			
		||||
	{
 | 
			
		||||
		super(sender);
 | 
			
		||||
		chunks = PS.getDistinctChunks(chunks);
 | 
			
		||||
		this.chunks = Collections.unmodifiableSet(chunks);
 | 
			
		||||
		this.newFaction = newFaction;
 | 
			
		||||
		this.oldChunkFaction = Collections.unmodifiableMap(BoardColl.getChunkFaction(chunks));
 | 
			
		||||
		this.oldFactionChunks = Collections.unmodifiableMap(MUtil.reverseIndex(this.oldChunkFaction));
 | 
			
		||||
		
 | 
			
		||||
		MPlayer msender = this.getMSender();
 | 
			
		||||
		Faction self = null;
 | 
			
		||||
		if (msender != null) self = msender.getFaction();
 | 
			
		||||
		Map<PS, EventFactionsChunkChangeType> currentChunkType = new LinkedHashMap<PS, EventFactionsChunkChangeType>();
 | 
			
		||||
		for (Entry<PS, Faction> entry : this.oldChunkFaction.entrySet())
 | 
			
		||||
		{
 | 
			
		||||
			PS chunk = entry.getKey();
 | 
			
		||||
			Faction from = entry.getValue();
 | 
			
		||||
			currentChunkType.put(chunk, EventFactionsChunkChangeType.get(from, newFaction, self));
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		this.chunkType = Collections.unmodifiableMap(currentChunkType);
 | 
			
		||||
		this.typeChunks = Collections.unmodifiableMap(MUtil.reverseIndex(this.chunkType));
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
@@ -1,6 +1,9 @@
 | 
			
		||||
package com.massivecraft.factions.integration.lwc;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Map.Entry;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import org.bukkit.Bukkit;
 | 
			
		||||
import org.bukkit.event.EventHandler;
 | 
			
		||||
@@ -14,7 +17,7 @@ import com.massivecraft.factions.Factions;
 | 
			
		||||
import com.massivecraft.factions.entity.Faction;
 | 
			
		||||
import com.massivecraft.factions.entity.MConf;
 | 
			
		||||
import com.massivecraft.factions.entity.MPlayer;
 | 
			
		||||
import com.massivecraft.factions.event.EventFactionsChunkChange;
 | 
			
		||||
import com.massivecraft.factions.event.EventFactionsChunksChange;
 | 
			
		||||
import com.massivecraft.factions.event.EventFactionsChunkChangeType;
 | 
			
		||||
import com.massivecraft.massivecore.EngineAbstract;
 | 
			
		||||
import com.massivecraft.massivecore.ps.PS;
 | 
			
		||||
@@ -59,12 +62,9 @@ public class EngineLwc extends EngineAbstract
 | 
			
		||||
	// LISTENER
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	
 | 
			
		||||
	@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
 | 
			
		||||
	public void removeProtectionsOnChunkChange(EventFactionsChunkChange event)
 | 
			
		||||
	public void removeProtectionsOnChunkChange(Faction newFaction, EventFactionsChunkChangeType type, Set<PS> chunks)
 | 
			
		||||
	{
 | 
			
		||||
		// If we are supposed to clear at this chunk change type ...
 | 
			
		||||
		Faction newFaction = event.getNewFaction();
 | 
			
		||||
		EventFactionsChunkChangeType type = event.getType();
 | 
			
		||||
		Boolean remove = MConf.get().lwcRemoveOnChange.get(type);
 | 
			
		||||
		if (remove == null) return;
 | 
			
		||||
		if (remove == false) return;
 | 
			
		||||
@@ -72,7 +72,26 @@ public class EngineLwc extends EngineAbstract
 | 
			
		||||
		// ... then remove for all other factions than the new one.
 | 
			
		||||
		// First we wait one tick to make sure the chunk ownership changes have been applied.
 | 
			
		||||
		// Then we remove the protections but we do it asynchronously to not lock the main thread.
 | 
			
		||||
		removeAlienProtectionsAsyncNextTick(event.getChunk(), newFaction);
 | 
			
		||||
		for (PS chunk : chunks)
 | 
			
		||||
		{
 | 
			
		||||
			removeAlienProtectionsAsyncNextTick(chunk, newFaction);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public void removeProtectionsOnChunkChange(Faction newFaction, Map<EventFactionsChunkChangeType, Set<PS>> typeChunks)
 | 
			
		||||
	{
 | 
			
		||||
		for (Entry<EventFactionsChunkChangeType, Set<PS>> typeChunk : typeChunks.entrySet())
 | 
			
		||||
		{
 | 
			
		||||
			final EventFactionsChunkChangeType type = typeChunk.getKey();
 | 
			
		||||
			final Set<PS> chunks = typeChunk.getValue();
 | 
			
		||||
			removeProtectionsOnChunkChange(newFaction, type, chunks);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
 | 
			
		||||
	public void removeProtectionsOnChunkChange(EventFactionsChunksChange event)
 | 
			
		||||
	{
 | 
			
		||||
		removeProtectionsOnChunkChange(event.getNewFaction(), event.getTypeChunks());
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
 
 | 
			
		||||
@@ -1,216 +0,0 @@
 | 
			
		||||
package com.massivecraft.factions.task;
 | 
			
		||||
 | 
			
		||||
import java.util.logging.Level;
 | 
			
		||||
 | 
			
		||||
import org.bukkit.Bukkit;
 | 
			
		||||
import org.bukkit.Location;
 | 
			
		||||
import org.bukkit.World;
 | 
			
		||||
 | 
			
		||||
import com.massivecraft.factions.Factions;
 | 
			
		||||
import com.massivecraft.massivecore.ps.PS;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * reference diagram, task should move in this pattern out from chunk 0 in the center.
 | 
			
		||||
 *  8 [>][>][>][>][>] etc.
 | 
			
		||||
 * [^][6][>][>][>][>][>][6]
 | 
			
		||||
 * [^][^][4][>][>][>][4][v]
 | 
			
		||||
 * [^][^][^][2][>][2][v][v]
 | 
			
		||||
 * [^][^][^][^][0][v][v][v]
 | 
			
		||||
 * [^][^][^][1][1][v][v][v]
 | 
			
		||||
 * [^][^][3][<][<][3][v][v]
 | 
			
		||||
 * [^][5][<][<][<][<][5][v]
 | 
			
		||||
 * [7][<][<][<][<][<][<][7]
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
public abstract class SpiralTask implements Runnable
 | 
			
		||||
{
 | 
			
		||||
	// general task-related reference data
 | 
			
		||||
	private transient World world = null;
 | 
			
		||||
	private transient boolean readyToGo = false;
 | 
			
		||||
	private transient int taskID = -1;
 | 
			
		||||
	private transient int limit = 0;
 | 
			
		||||
 | 
			
		||||
	// values for the spiral pattern routine
 | 
			
		||||
	private transient int x = 0;
 | 
			
		||||
	private transient int z = 0;
 | 
			
		||||
	private transient boolean isZLeg = false;
 | 
			
		||||
	private transient boolean isNeg = false;
 | 
			
		||||
	private transient int length = -1;
 | 
			
		||||
	private transient int current = 0;
 | 
			
		||||
 | 
			
		||||
	// @SuppressWarnings("LeakingThisInConstructor") This actually triggers a warning in Eclipse xD Could we find another way to suppress the error please? :)
 | 
			
		||||
	public SpiralTask(PS chunk, int radius)
 | 
			
		||||
	{
 | 
			
		||||
		chunk = chunk.getChunk(true);
 | 
			
		||||
		
 | 
			
		||||
		// limit is determined based on spiral leg length for given radius; see insideRadius()
 | 
			
		||||
		this.limit = (radius - 1) * 2;
 | 
			
		||||
 | 
			
		||||
		this.world = Bukkit.getWorld(chunk.getWorld());
 | 
			
		||||
		if (this.world == null)
 | 
			
		||||
		{
 | 
			
		||||
			Factions.get().log(Level.WARNING, "[SpiralTask] A valid world must be specified!");
 | 
			
		||||
			this.stop();
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		this.x = (int)chunk.getChunkX();
 | 
			
		||||
		this.z = (int)chunk.getChunkZ();
 | 
			
		||||
 | 
			
		||||
		this.readyToGo = true;
 | 
			
		||||
 | 
			
		||||
		// get this party started
 | 
			
		||||
		this.setTaskID(Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(Factions.get(), this, 2, 2));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This is where the necessary work is done; you'll need to override this method with whatever you want
 | 
			
		||||
 * done at each chunk in the spiral pattern.
 | 
			
		||||
 * Return false if the entire task needs to be aborted, otherwise return true to continue.
 | 
			
		||||
 */
 | 
			
		||||
	public abstract boolean work();
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Returns a PS pointing at the current chunk X and Z values.
 | 
			
		||||
 */
 | 
			
		||||
	public final PS currentChunk()
 | 
			
		||||
	{
 | 
			
		||||
		return PS.valueOf(this.world.getName(), null, null, null, null, null, null, this.x, this.z, null, null, null, null, null);
 | 
			
		||||
	}
 | 
			
		||||
/*
 | 
			
		||||
 * Returns a Location pointing at the current chunk X and Z values.
 | 
			
		||||
 * note that the Location is at the corner of the chunk, not the center.
 | 
			
		||||
 */
 | 
			
		||||
	public final Location currentLocation()
 | 
			
		||||
	{
 | 
			
		||||
		
 | 
			
		||||
		return new Location(world, this.x * 16, 65.0, this.z * 16);
 | 
			
		||||
	}
 | 
			
		||||
/*
 | 
			
		||||
 * Returns current chunk X and Z values.
 | 
			
		||||
 */
 | 
			
		||||
	public final int getX()
 | 
			
		||||
	{
 | 
			
		||||
		return x;
 | 
			
		||||
	}
 | 
			
		||||
	public final int getZ()
 | 
			
		||||
	{
 | 
			
		||||
		return z;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Below are the guts of the class, which you normally wouldn't need to mess with.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
	public final void setTaskID(int ID)
 | 
			
		||||
	{	
 | 
			
		||||
		if (ID == -1)
 | 
			
		||||
			this.stop();
 | 
			
		||||
		taskID = ID;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public final void run()
 | 
			
		||||
	{
 | 
			
		||||
		if (!this.valid() || !readyToGo) return;
 | 
			
		||||
 | 
			
		||||
		// this is set so it only does one iteration at a time, no matter how frequently the timer fires
 | 
			
		||||
		readyToGo = false;
 | 
			
		||||
 | 
			
		||||
		// make sure we're still inside the specified radius
 | 
			
		||||
		if ( ! this.insideRadius()) return;
 | 
			
		||||
 | 
			
		||||
		// track this to keep one iteration from dragging on too long and possibly choking the system
 | 
			
		||||
		long loopStartTime = now();
 | 
			
		||||
 | 
			
		||||
		// keep going until the task has been running for 20ms or more, then stop to take a breather
 | 
			
		||||
		while (now() < loopStartTime + 20)
 | 
			
		||||
		{
 | 
			
		||||
			// run the primary task on the current X/Z coordinates
 | 
			
		||||
			if ( ! this.work())
 | 
			
		||||
			{
 | 
			
		||||
				this.finish();
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// move on to next chunk in spiral
 | 
			
		||||
			if ( ! this.moveToNext())
 | 
			
		||||
				return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// ready for the next iteration to run
 | 
			
		||||
		readyToGo = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// step through chunks in spiral pattern from center; returns false if we're done, otherwise returns true
 | 
			
		||||
	public final boolean moveToNext()
 | 
			
		||||
	{
 | 
			
		||||
		if ( ! this.valid()) return false;
 | 
			
		||||
 | 
			
		||||
		// make sure we don't need to turn down the next leg of the spiral
 | 
			
		||||
		if (current < length)
 | 
			
		||||
		{
 | 
			
		||||
			current++;
 | 
			
		||||
 | 
			
		||||
			// if we're outside the radius, we're done
 | 
			
		||||
			if ( ! this.insideRadius()) return false;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{	// one leg/side of the spiral down...
 | 
			
		||||
			current = 0;
 | 
			
		||||
			isZLeg ^= true;
 | 
			
		||||
			// every second leg (between X and Z legs, negative or positive), length increases
 | 
			
		||||
			if (isZLeg)
 | 
			
		||||
			{
 | 
			
		||||
				isNeg ^= true;
 | 
			
		||||
				length++;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// move one chunk further in the appropriate direction
 | 
			
		||||
		if (isZLeg)
 | 
			
		||||
			z += (isNeg) ? -1 : 1;
 | 
			
		||||
		else
 | 
			
		||||
			x += (isNeg) ? -1 : 1;
 | 
			
		||||
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public final boolean insideRadius()
 | 
			
		||||
	{
 | 
			
		||||
		boolean inside = current < limit;
 | 
			
		||||
		if (!inside)
 | 
			
		||||
			this.finish();
 | 
			
		||||
		return inside;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// for successful completion
 | 
			
		||||
	public void finish()
 | 
			
		||||
	{
 | 
			
		||||
//		P.p.log("SpiralTask successfully completed!");
 | 
			
		||||
		this.stop();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// we're done, whether finished or cancelled
 | 
			
		||||
	public final void stop()
 | 
			
		||||
	{
 | 
			
		||||
		if (!this.valid()) return;
 | 
			
		||||
 | 
			
		||||
		readyToGo = false;
 | 
			
		||||
		Bukkit.getServer().getScheduler().cancelTask(taskID);
 | 
			
		||||
		taskID = -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// is this task still valid/workable?
 | 
			
		||||
	public final boolean valid()
 | 
			
		||||
	{
 | 
			
		||||
		return taskID != -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static long now()
 | 
			
		||||
	{
 | 
			
		||||
		return System.currentTimeMillis();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user