This commit is contained in:
Ryan Hamshire 2012-11-07 17:36:25 -08:00
parent 6632af96df
commit e09a6732ba
12 changed files with 8839 additions and 8696 deletions

View File

@ -1,178 +1,178 @@
name: GriefPrevention name: GriefPrevention
main: me.ryanhamshire.GriefPrevention.GriefPrevention main: me.ryanhamshire.GriefPrevention.GriefPrevention
softdepend: [Vault, Multiverse-Core, My Worlds, MystCraft, Transporter] softdepend: [Vault, Multiverse-Core, My Worlds, MystCraft, Transporter]
dev-url: http://dev.bukkit.org/server-mods/grief-prevention dev-url: http://dev.bukkit.org/server-mods/grief-prevention
version: 6.7 version: 6.9
commands: commands:
abandonclaim: abandonclaim:
description: Deletes a claim. description: Deletes a claim.
usage: /AbandonClaim usage: /AbandonClaim
permission: griefprevention.claims permission: griefprevention.claims
abandontoplevelclaim: abandontoplevelclaim:
description: Deletes a claim and all its subdivisions. description: Deletes a claim and all its subdivisions.
usage: /AbandonTopLevelClaim usage: /AbandonTopLevelClaim
permission: griefprevention.claims permission: griefprevention.claims
abandonallclaims: abandonallclaims:
description: Deletes ALL your claims. description: Deletes ALL your claims.
usage: /AbandonAllClaims usage: /AbandonAllClaims
permission: griefprevention.claims permission: griefprevention.claims
trust: trust:
description: Grants a player full access to your claim(s). description: Grants a player full access to your claim(s).
usage: /Trust <player> Graants a player permission to build. See also /UnTrust, /ContainerTrust, /AccessTrust, and /PermissionTrust. usage: /Trust <player> Graants a player permission to build. See also /UnTrust, /ContainerTrust, /AccessTrust, and /PermissionTrust.
aliases: tr aliases: tr
permission: griefprevention.claims permission: griefprevention.claims
untrust: untrust:
description: Revokes a player's access to your claim(s). description: Revokes a player's access to your claim(s).
usage: /UnTrust <player> usage: /UnTrust <player>
aliases: ut aliases: ut
permission: griefprevention.claims permission: griefprevention.claims
containertrust: containertrust:
description: Grants a player access to your containers. description: Grants a player access to your containers.
usage: /ContainerTrust <player>. Grants a player access to your inventory, bed, and buttons/levers. usage: /ContainerTrust <player>. Grants a player access to your inventory, bed, and buttons/levers.
aliases: ct aliases: ct
permission: griefprevention.claims permission: griefprevention.claims
accesstrust: accesstrust:
description: Grants a player entry to your claim(s) and use of your bed. description: Grants a player entry to your claim(s) and use of your bed.
usage: /AccessTrust <player>. Grants a player access to your bed, buttons, and levers. usage: /AccessTrust <player>. Grants a player access to your bed, buttons, and levers.
aliases: at aliases: at
permission: griefprevention.claims permission: griefprevention.claims
permissiontrust: permissiontrust:
description: Grants a player permission to grant his level of permission to others. description: Grants a player permission to grant his level of permission to others.
usage: /PermissionTrust <player>. Permits a player to share his permission level with others. usage: /PermissionTrust <player>. Permits a player to share his permission level with others.
aliases: pt aliases: pt
permission: griefprevention.claims permission: griefprevention.claims
subdivideclaims: subdivideclaims:
description: Switches the shovel tool to subdivision mode, used to subdivide your claims. description: Switches the shovel tool to subdivision mode, used to subdivide your claims.
usage: /SubdivideClaims usage: /SubdivideClaims
aliases: sc aliases: sc
permission: griefprevention.claims permission: griefprevention.claims
adjustbonusclaimblocks: adjustbonusclaimblocks:
description: Adds or subtracts bonus claim blocks for a player. description: Adds or subtracts bonus claim blocks for a player.
usage: /AdjustBonusClaimBlocks <player> <amount> usage: /AdjustBonusClaimBlocks <player> <amount>
permission: griefprevention.adjustclaimblocks permission: griefprevention.adjustclaimblocks
aliases: acb aliases: acb
deleteclaim: deleteclaim:
description: Deletes the claim you're standing in, even if it's not your claim. description: Deletes the claim you're standing in, even if it's not your claim.
usage: /DeleteClaim usage: /DeleteClaim
permission: griefprevention.deleteclaims permission: griefprevention.deleteclaims
aliases: dc aliases: dc
deleteallclaims: deleteallclaims:
description: Deletes all of another player's claims. description: Deletes all of another player's claims.
usage: /DeleteAllClaims <player> usage: /DeleteAllClaims <player>
permission: griefprevention.deleteclaims permission: griefprevention.deleteclaims
adminclaims: adminclaims:
description: Switches the shovel tool to administrative claims mode. description: Switches the shovel tool to administrative claims mode.
usage: /AdminClaims usage: /AdminClaims
permission: griefprevention.adminclaims permission: griefprevention.adminclaims
aliases: ac aliases: ac
restorenature: restorenature:
description: Switches the shovel tool to restoration mode. description: Switches the shovel tool to restoration mode.
usage: /RestoreNature usage: /RestoreNature
permission: griefprevention.restorenature permission: griefprevention.restorenature
aliases: rn aliases: rn
restorenatureaggressive: restorenatureaggressive:
description: Switches the shovel tool to aggressive restoration mode. description: Switches the shovel tool to aggressive restoration mode.
usage: /RestoreNatureAggressive usage: /RestoreNatureAggressive
permission: griefprevention.restorenatureaggressive permission: griefprevention.restorenatureaggressive
aliases: rna aliases: rna
restorenaturefill: restorenaturefill:
description: Switches the shovel tool to fill mode. description: Switches the shovel tool to fill mode.
usage: /RestoreNatureFill <radius> usage: /RestoreNatureFill <radius>
permission: griefprevention.restorenatureaggressive permission: griefprevention.restorenatureaggressive
aliases: rnf aliases: rnf
basicclaims: basicclaims:
description: Switches the shovel tool back to basic claims mode. description: Switches the shovel tool back to basic claims mode.
usage: /BasicClaims usage: /BasicClaims
aliases: bc aliases: bc
permission: griefprevention.claims permission: griefprevention.claims
buyclaimblocks: buyclaimblocks:
description: Purchases additional claim blocks with server money. Doesn't work on servers without a Vault-compatible economy plugin. description: Purchases additional claim blocks with server money. Doesn't work on servers without a Vault-compatible economy plugin.
usage: /BuyClaimBlocks <numberOfBlocks> usage: /BuyClaimBlocks <numberOfBlocks>
aliases: buyclaim aliases: buyclaim
permission: griefprevention.claims permission: griefprevention.claims
sellclaimblocks: sellclaimblocks:
description: Sells your claim blocks for server money. Doesn't work on servers without a Vault-compatible economy plugin. description: Sells your claim blocks for server money. Doesn't work on servers without a Vault-compatible economy plugin.
usage: /SellClaimBlocks <numberOfBlocks> usage: /SellClaimBlocks <numberOfBlocks>
aliases: sellclaim aliases: sellclaim
permission: griefprevention.claims permission: griefprevention.claims
trapped: trapped:
description: Ejects you to nearby unclaimed land. Has a substantial cooldown period. description: Ejects you to nearby unclaimed land. Has a substantial cooldown period.
usage: /Trapped usage: /Trapped
trustlist: trustlist:
description: Lists permissions for the claim you're standing in. description: Lists permissions for the claim you're standing in.
usage: /TrustList usage: /TrustList
permission: griefprevention.claims permission: griefprevention.claims
siege: siege:
description: Initiates a siege versus another player. description: Initiates a siege versus another player.
usage: /Siege <playerName> usage: /Siege <playerName>
ignoreclaims: ignoreclaims:
description: Toggles ignore claims mode. description: Toggles ignore claims mode.
usage: /IgnoreClaims usage: /IgnoreClaims
permission: griefprevention.ignoreclaims permission: griefprevention.ignoreclaims
aliases: ic aliases: ic
deletealladminclaims: deletealladminclaims:
description: Deletes all administrative claims. description: Deletes all administrative claims.
usage: /DeleteAllAdminClaims usage: /DeleteAllAdminClaims
permission: griefprevention.adminclaims permission: griefprevention.adminclaims
transferclaim: transferclaim:
description: Converts an administrative claim to a private claim. description: Converts an administrative claim to a private claim.
usage: /TransferClaim <player> usage: /TransferClaim <player>
permission: griefprevention.adjustclaimblocks permission: griefprevention.adjustclaimblocks
deathblow: deathblow:
description: Kills a player, optionally giving his inventory to another player. description: Kills a player, optionally giving his inventory to another player.
usage: /DeathBlow <player> [recipientPlayer] usage: /DeathBlow <player> [recipientPlayer]
permission: griefprevention.deathblow permission: griefprevention.deathblow
claimslist: claimslist:
description: Lists information about a player's claim blocks and claims. description: Lists information about a player's claim blocks and claims.
usage: /ClaimsList <player> usage: /ClaimsList <player>
permission: griefprevention.adjustclaimblocks permission: griefprevention.adjustclaimblocks
permissions: permissions:
griefprevention.createclaims: griefprevention.createclaims:
description: Grants permission to create claims. description: Grants permission to create claims.
default: op default: op
griefprevention.admin.*: griefprevention.admin.*:
description: Grants all administrative functionality. description: Grants all administrative functionality.
children: children:
griefprevention.restorenature: true griefprevention.restorenature: true
griefprevention.restorenatureaggressive: true griefprevention.restorenatureaggressive: true
griefprevention.ignoreclaims: true griefprevention.ignoreclaims: true
griefprevention.adminclaims: true griefprevention.adminclaims: true
griefprevention.adjustclaimblocks: true griefprevention.adjustclaimblocks: true
griefprevention.deleteclaims: true griefprevention.deleteclaims: true
griefprevention.spam: true griefprevention.spam: true
griefprevention.lava: true griefprevention.lava: true
griefprevention.eavesdrop: true griefprevention.eavesdrop: true
griefprevention.deathblow: true griefprevention.deathblow: true
griefprevention.restorenature: griefprevention.restorenature:
description: Grants permission to use /RestoreNature. description: Grants permission to use /RestoreNature.
default: op default: op
griefprevention.ignoreclaims: griefprevention.ignoreclaims:
description: Grants permission to use /IgnoreClaims. description: Grants permission to use /IgnoreClaims.
default: op default: op
griefprevention.adminclaims: griefprevention.adminclaims:
description: Grants permission to create administrative claims. description: Grants permission to create administrative claims.
default: op default: op
griefprevention.deleteclaims: griefprevention.deleteclaims:
description: Grants permission to delete other players' claims. description: Grants permission to delete other players' claims.
default: op default: op
griefprevention.adjustclaimblocks: griefprevention.adjustclaimblocks:
description: Grants permission to add or remove bonus blocks from a player's account. description: Grants permission to add or remove bonus blocks from a player's account.
default: op default: op
griefprevention.spam: griefprevention.spam:
description: Grants permission to log in, send messages, and send commands rapidly. description: Grants permission to log in, send messages, and send commands rapidly.
default: op default: op
griefprevention.lava: griefprevention.lava:
description: Grants permission to place lava near the surface and outside of claims. description: Grants permission to place lava near the surface and outside of claims.
default: op default: op
griefprevention.eavesdrop: griefprevention.eavesdrop:
description: Allows a player to see whispered chat messages (/tell). description: Allows a player to see whispered chat messages (/tell).
default: op default: op
griefprevention.restorenatureaggressive: griefprevention.restorenatureaggressive:
description: Grants access to /RestoreNatureAggressive and /RestoreNatureFill. description: Grants access to /RestoreNatureAggressive and /RestoreNatureFill.
default: op default: op
griefprevention.deathblow: griefprevention.deathblow:
description: Grants access to /DeathBlow. description: Grants access to /DeathBlow.
default: op default: op
griefprevention.claims: griefprevention.claims:
description: Grants access to claim-related slash commands. description: Grants access to claim-related slash commands.
default: true default: true

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,189 +1,215 @@
/* /*
GriefPrevention Server Plugin for Minecraft GriefPrevention Server Plugin for Minecraft
Copyright (C) 2011 Ryan Hamshire Copyright (C) 2011 Ryan Hamshire
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package me.ryanhamshire.GriefPrevention; package me.ryanhamshire.GriefPrevention;
import java.util.Calendar; import java.util.Calendar;
import java.util.Random; import java.util.Random;
import java.util.Vector;
import org.bukkit.Chunk;
import org.bukkit.World; import org.bukkit.Chunk;
import org.bukkit.World;
//FEATURE: automatically remove claims owned by inactive players which:
//...aren't protecting much OR //FEATURE: automatically remove claims owned by inactive players which:
//...are a free new player claim (and the player has no other claims) OR //...aren't protecting much OR
//...because the player has been gone a REALLY long time, and that expiration has been configured in config.yml //...are a free new player claim (and the player has no other claims) OR
//...because the player has been gone a REALLY long time, and that expiration has been configured in config.yml
//runs every 1 minute in the main thread
class CleanupUnusedClaimsTask implements Runnable //runs every 1 minute in the main thread
{ class CleanupUnusedClaimsTask implements Runnable
int nextClaimIndex; {
int nextClaimIndex;
CleanupUnusedClaimsTask()
{ CleanupUnusedClaimsTask()
//start scanning in a random spot {
if(GriefPrevention.instance.dataStore.claims.size() == 0) //start scanning in a random spot
{ if(GriefPrevention.instance.dataStore.claims.size() == 0)
this.nextClaimIndex = 0; {
} this.nextClaimIndex = 0;
else }
{ else
Random randomNumberGenerator = new Random(); {
this.nextClaimIndex = randomNumberGenerator.nextInt(GriefPrevention.instance.dataStore.claims.size()); Random randomNumberGenerator = new Random();
} this.nextClaimIndex = randomNumberGenerator.nextInt(GriefPrevention.instance.dataStore.claims.size());
} }
}
@Override
public void run() @Override
{ public void run()
//don't do anything when there are no claims {
if(GriefPrevention.instance.dataStore.claims.size() == 0) return; //don't do anything when there are no claims
if(GriefPrevention.instance.dataStore.claims.size() == 0) return;
//wrap search around to beginning
if(this.nextClaimIndex >= GriefPrevention.instance.dataStore.claims.size()) this.nextClaimIndex = 0; //wrap search around to beginning
if(this.nextClaimIndex >= GriefPrevention.instance.dataStore.claims.size()) this.nextClaimIndex = 0;
//decide which claim to check next
Claim claim = GriefPrevention.instance.dataStore.claims.get(this.nextClaimIndex++); //decide which claim to check next
Claim claim = GriefPrevention.instance.dataStore.claims.get(this.nextClaimIndex++);
//skip administrative claims
if(claim.isAdminClaim()) return; //skip administrative claims
if(claim.isAdminClaim()) return;
//get data for the player, especially last login timestamp
PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(claim.ownerName); //track whether we do any important work which would require cleanup afterward
boolean cleanupChunks = false;
//determine area of the default chest claim
int areaOfDefaultClaim = 0; //get data for the player, especially last login timestamp
if(GriefPrevention.instance.config_claims_automaticClaimsForNewPlayersRadius >= 0) PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(claim.ownerName);
{
areaOfDefaultClaim = (int)Math.pow(GriefPrevention.instance.config_claims_automaticClaimsForNewPlayersRadius * 2 + 1, 2); //determine area of the default chest claim
} int areaOfDefaultClaim = 0;
if(GriefPrevention.instance.config_claims_automaticClaimsForNewPlayersRadius >= 0)
//if he's been gone at least a week, if he has ONLY the new player claim, it will be removed {
Calendar sevenDaysAgo = Calendar.getInstance(); areaOfDefaultClaim = (int)Math.pow(GriefPrevention.instance.config_claims_automaticClaimsForNewPlayersRadius * 2 + 1, 2);
sevenDaysAgo.add(Calendar.DATE, -7); }
boolean newPlayerClaimsExpired = sevenDaysAgo.getTime().after(playerData.lastLogin);
//if he's been gone at least a week, if he has ONLY the new player claim, it will be removed
//if only one claim, and the player hasn't played in a week Calendar sevenDaysAgo = Calendar.getInstance();
if(newPlayerClaimsExpired && playerData.claims.size() == 1) sevenDaysAgo.add(Calendar.DATE, -GriefPrevention.instance.config_claims_chestClaimExpirationDays);
{ boolean newPlayerClaimsExpired = sevenDaysAgo.getTime().after(playerData.lastLogin);
//if that's a chest claim, delete it
if(claim.getArea() <= areaOfDefaultClaim) //if only one claim, and the player hasn't played in a week
{ if(newPlayerClaimsExpired && playerData.claims.size() == 1)
claim.removeSurfaceFluids(null); {
GriefPrevention.instance.dataStore.deleteClaim(claim); //if that's a chest claim and those are set to expire
if(claim.getArea() <= areaOfDefaultClaim && GriefPrevention.instance.config_claims_chestClaimExpirationDays > 0)
//if in a creative mode world, delete the claim {
if(GriefPrevention.instance.creativeRulesApply(claim.getLesserBoundaryCorner())) claim.removeSurfaceFluids(null);
{ GriefPrevention.instance.dataStore.deleteClaim(claim);
GriefPrevention.instance.restoreClaim(claim, 0); cleanupChunks = true;
}
//if configured to do so, restore the land to natural
GriefPrevention.AddLogEntry(" " + claim.getOwnerName() + "'s new player claim expired."); if((GriefPrevention.instance.creativeRulesApply(claim.getLesserBoundaryCorner()) && GriefPrevention.instance.config_claims_creativeAutoNatureRestoration) || GriefPrevention.instance.config_claims_survivalAutoNatureRestoration)
} {
} GriefPrevention.instance.restoreClaim(claim, 0);
}
//if configured to always remove claims after some inactivity period without exceptions...
else if(GriefPrevention.instance.config_claims_expirationDays > 0) GriefPrevention.AddLogEntry(" " + claim.getOwnerName() + "'s new player claim expired.");
{ }
Calendar earliestPermissibleLastLogin = Calendar.getInstance(); }
earliestPermissibleLastLogin.add(Calendar.DATE, -GriefPrevention.instance.config_claims_expirationDays);
//if configured to always remove claims after some inactivity period without exceptions...
if(earliestPermissibleLastLogin.getTime().after(playerData.lastLogin)) else if(GriefPrevention.instance.config_claims_expirationDays > 0)
{ {
GriefPrevention.instance.dataStore.deleteClaimsForPlayer(claim.getOwnerName(), true); Calendar earliestPermissibleLastLogin = Calendar.getInstance();
GriefPrevention.AddLogEntry(" All of " + claim.getOwnerName() + "'s claims have expired."); earliestPermissibleLastLogin.add(Calendar.DATE, -GriefPrevention.instance.config_claims_expirationDays);
}
} if(earliestPermissibleLastLogin.getTime().after(playerData.lastLogin))
{
else //make a copy of this player's claim list
{ Vector<Claim> claims = new Vector<Claim>();
for(int i = 0; i < playerData.claims.size(); i++)
//if the player has been gone two weeks, scan claim content to assess player investment {
Calendar fourteenDaysAgo = Calendar.getInstance(); claims.add(playerData.claims.get(i));
fourteenDaysAgo.add(Calendar.DATE, -14); }
boolean needsInvestmentScan = fourteenDaysAgo.getTime().after(playerData.lastLogin);
//delete them
//avoid scanning large claims and administrative claims GriefPrevention.instance.dataStore.deleteClaimsForPlayer(claim.getOwnerName(), true);
if(claim.isAdminClaim() || claim.getWidth() > 25 || claim.getHeight() > 25) return; GriefPrevention.AddLogEntry(" All of " + claim.getOwnerName() + "'s claims have expired.");
//if creative mode or the claim owner has been away a long enough time, scan the claim content for(int i = 0; i < claims.size(); i++)
if(needsInvestmentScan || GriefPrevention.instance.creativeRulesApply(claim.getLesserBoundaryCorner())) {
{ //if configured to do so, restore the land to natural
int minInvestment; if((GriefPrevention.instance.creativeRulesApply(claims.get(i).getLesserBoundaryCorner()) && GriefPrevention.instance.config_claims_creativeAutoNatureRestoration) || GriefPrevention.instance.config_claims_survivalAutoNatureRestoration)
if(GriefPrevention.instance.creativeRulesApply(claim.getLesserBoundaryCorner())) {
{ GriefPrevention.instance.restoreClaim(claims.get(i), 0);
minInvestment = 400; cleanupChunks = true;
} }
else }
{ }
minInvestment = 200; }
}
else if(GriefPrevention.instance.config_claims_unusedClaimExpirationDays > 0)
long investmentScore = claim.getPlayerInvestmentScore(); {
boolean removeClaim = false; //if the player has been gone two weeks, scan claim content to assess player investment
Calendar earliestAllowedLoginDate = Calendar.getInstance();
//in creative mode, a build which is almost entirely lava above sea level will be automatically removed, even if the owner is an active player earliestAllowedLoginDate.add(Calendar.DATE, -GriefPrevention.instance.config_claims_unusedClaimExpirationDays);
//lava above the surface deducts 10 points per block from the investment score boolean needsInvestmentScan = earliestAllowedLoginDate.getTime().after(playerData.lastLogin);
//so 500 blocks of lava without anything built to offset all that potential mess would be cleaned up automatically
if(GriefPrevention.instance.creativeRulesApply(claim.getLesserBoundaryCorner()) && investmentScore < -5000) //avoid scanning large claims and administrative claims
{ if(claim.isAdminClaim() || claim.getWidth() > 25 || claim.getHeight() > 25) return;
removeClaim = true;
} //if creative mode or the claim owner has been away a long enough time, scan the claim content
if(needsInvestmentScan || GriefPrevention.instance.creativeRulesApply(claim.getLesserBoundaryCorner()))
//otherwise, the only way to get a claim automatically removed based on build investment is to be away for two weeks AND not build much of anything {
else if(needsInvestmentScan && investmentScore < minInvestment) int minInvestment;
{ if(GriefPrevention.instance.creativeRulesApply(claim.getLesserBoundaryCorner()))
removeClaim = true; {
} minInvestment = 400;
}
if(removeClaim) else
{ {
GriefPrevention.instance.dataStore.deleteClaim(claim); minInvestment = 100;
GriefPrevention.AddLogEntry("Removed " + claim.getOwnerName() + "'s unused claim @ " + GriefPrevention.getfriendlyLocationString(claim.getLesserBoundaryCorner())); }
//if in a creative mode world, restore the claim area long investmentScore = claim.getPlayerInvestmentScore();
if(GriefPrevention.instance.creativeRulesApply(claim.getLesserBoundaryCorner())) cleanupChunks = true;
{ boolean removeClaim = false;
GriefPrevention.instance.restoreClaim(claim, 0);
} //in creative mode, a build which is almost entirely lava above sea level will be automatically removed, even if the owner is an active player
} //lava above the surface deducts 10 points per block from the investment score
} //so 500 blocks of lava without anything built to offset all that potential mess would be cleaned up automatically
} if(GriefPrevention.instance.creativeRulesApply(claim.getLesserBoundaryCorner()) && investmentScore < -5000)
{
//toss that player data out of the cache, it's probably not needed in memory right now removeClaim = true;
if(!GriefPrevention.instance.getServer().getOfflinePlayer(claim.ownerName).isOnline()) }
{
GriefPrevention.instance.dataStore.clearCachedPlayerData(claim.ownerName); //otherwise, the only way to get a claim automatically removed based on build investment is to be away for two weeks AND not build much of anything
} else if(needsInvestmentScan && investmentScore < minInvestment)
{
//since we're potentially loading a lot of chunks to scan parts of the world where there are no players currently playing, be mindful of memory usage removeClaim = true;
//unfortunately, java/minecraft don't do a good job of clearing unused memory, leading to out of memory errors from this type of world scanning }
if(this.nextClaimIndex % 20 == 0)
{ if(removeClaim)
World world = claim.getLesserBoundaryCorner().getWorld(); {
Chunk [] chunks = world.getLoadedChunks(); GriefPrevention.instance.dataStore.deleteClaim(claim);
for(int i = 0; i < chunks.length; i++) GriefPrevention.AddLogEntry("Removed " + claim.getOwnerName() + "'s unused claim @ " + GriefPrevention.getfriendlyLocationString(claim.getLesserBoundaryCorner()));
{
Chunk chunk = chunks[i]; //if configured to do so, restore the claim area to natural state
chunk.unload(true, true); if((GriefPrevention.instance.creativeRulesApply(claim.getLesserBoundaryCorner()) && GriefPrevention.instance.config_claims_creativeAutoNatureRestoration) || GriefPrevention.instance.config_claims_survivalAutoNatureRestoration)
} {
GriefPrevention.instance.restoreClaim(claim, 0);
System.gc(); }
} }
} }
} }
//toss that player data out of the cache, it's probably not needed in memory right now
if(!GriefPrevention.instance.getServer().getOfflinePlayer(claim.ownerName).isOnline())
{
GriefPrevention.instance.dataStore.clearCachedPlayerData(claim.ownerName);
}
//since we're potentially loading a lot of chunks to scan parts of the world where there are no players currently playing, be mindful of memory usage
if(cleanupChunks)
{
World world = claim.getLesserBoundaryCorner().getWorld();
Chunk [] chunks = world.getLoadedChunks();
for(int i = 0; i < chunks.length; i++)
{
Chunk chunk = chunks[i];
chunk.unload(true, true);
}
}
//unfortunately, java/minecraft don't do a good job of clearing unused memory, leading to out of memory errors from this type of world scanning
if(this.nextClaimIndex % 10 == 0)
{
System.gc();
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
package me.ryanhamshire.GriefPrevention; package me.ryanhamshire.GriefPrevention;
public enum Messages public enum Messages
{ {
RespectingClaims, IgnoringClaims, SuccessfulAbandon, RestoreNatureActivate, RestoreNatureAggressiveActivate, FillModeActive, TransferClaimPermission, TransferClaimMissing, TransferClaimAdminOnly, PlayerNotFound, TransferTopLevel, TransferSuccess, TrustListNoClaim, ClearPermsOwnerOnly, UntrustIndividualAllClaims, UntrustEveryoneAllClaims, NoPermissionTrust, ClearPermissionsOneClaim, UntrustIndividualSingleClaim, OnlySellBlocks, BlockPurchaseCost, ClaimBlockLimit, InsufficientFunds, PurchaseConfirmation, OnlyPurchaseBlocks, BlockSaleValue, NotEnoughBlocksForSale, BlockSaleConfirmation, AdminClaimsMode, BasicClaimsMode, SubdivisionMode, SubdivisionDemo, DeleteClaimMissing, DeletionSubdivisionWarning, DeleteSuccess, CantDeleteAdminClaim, DeleteAllSuccess, NoDeletePermission, AllAdminDeleted, AdjustBlocksSuccess, NotTrappedHere, TrappedOnCooldown, RescuePending, NonSiegeWorld, AlreadySieging, NotSiegableThere, SiegeTooFarAway, NoSiegeDefenseless, AlreadyUnderSiegePlayer, AlreadyUnderSiegeArea, NoSiegeAdminClaim, SiegeOnCooldown, SiegeAlert, SiegeConfirmed, AbandonClaimMissing, NotYourClaim, DeleteTopLevelClaim, AbandonSuccess, CantGrantThatPermission, GrantPermissionNoClaim, GrantPermissionConfirmation, ManageUniversalPermissionsInstruction, ManageOneClaimPermissionsInstruction, CollectivePublic, BuildPermission, ContainersPermission, AccessPermission, PermissionsPermission, LocationCurrentClaim, LocationAllClaims, PvPImmunityStart, SiegeNoDrop, DonateItemsInstruction, ChestFull, DonationSuccess, PlayerTooCloseForFire, TooDeepToClaim, ChestClaimConfirmation, AutomaticClaimNotification, TrustCommandAdvertisement, GoldenShovelAdvertisement, UnprotectedChestWarning, ThatPlayerPvPImmune, CantFightWhileImmune, NoDamageClaimedEntity, ShovelBasicClaimMode, RemainingBlocks, CreativeBasicsDemoAdvertisement, SurvivalBasicsDemoAdvertisement, TrappedChatKeyword, TrappedInstructions, PvPNoDrop, SiegeNoTeleport, BesiegedNoTeleport, SiegeNoContainers, PvPNoContainers, PvPImmunityEnd, NoBedPermission, NoWildernessBuckets, NoLavaNearOtherPlayer, TooFarAway, BlockNotClaimed, BlockClaimed, SiegeNoShovel, RestoreNaturePlayerInChunk, NoCreateClaimPermission, ResizeClaimTooSmall, ResizeNeedMoreBlocks, NoCreativeUnClaim, ClaimResizeSuccess, ResizeFailOverlap, ResizeStart, ResizeFailOverlapSubdivision, SubdivisionStart, CreateSubdivisionOverlap, SubdivisionSuccess, CreateClaimFailOverlap, CreateClaimFailOverlapOtherPlayer, ClaimsDisabledWorld, ClaimStart, NewClaimTooSmall, CreateClaimInsufficientBlocks, AbandonClaimAdvertisement, CreateClaimFailOverlapShort, CreateClaimSuccess, SiegeWinDoorsOpen, RescueAbortedMoved, SiegeDoorsLockedEjection, NoModifyDuringSiege, OnlyOwnersModifyClaims, NoBuildUnderSiege, NoBuildPvP, NoBuildPermission, NonSiegeMaterial, NoOwnerBuildUnderSiege, NoAccessPermission, NoContainersSiege, NoContainersPermission, OwnerNameForAdminClaims, ClaimTooSmallForEntities, TooManyEntitiesInClaim, YouHaveNoClaims, ConfirmFluidRemoval, AutoBanNotify, AdjustGroupBlocksSuccess, InvalidPermissionID, UntrustOwnerOnly, HowToClaimRegex, NoBuildOutsideClaims, PlayerOfflineTime, BuildingOutsideClaims, TrappedWontWorkHere, CommandBannedInPvP, UnclaimCleanupWarning, BuySellNotConfigured, NoTeleportPvPCombat, NoTNTDamageAboveSeaLevel, NoTNTDamageClaims RespectingClaims, IgnoringClaims, SuccessfulAbandon, RestoreNatureActivate, RestoreNatureAggressiveActivate, FillModeActive, TransferClaimPermission, TransferClaimMissing, TransferClaimAdminOnly, PlayerNotFound, TransferTopLevel, TransferSuccess, TrustListNoClaim, ClearPermsOwnerOnly, UntrustIndividualAllClaims, UntrustEveryoneAllClaims, NoPermissionTrust, ClearPermissionsOneClaim, UntrustIndividualSingleClaim, OnlySellBlocks, BlockPurchaseCost, ClaimBlockLimit, InsufficientFunds, PurchaseConfirmation, OnlyPurchaseBlocks, BlockSaleValue, NotEnoughBlocksForSale, BlockSaleConfirmation, AdminClaimsMode, BasicClaimsMode, SubdivisionMode, SubdivisionDemo, DeleteClaimMissing, DeletionSubdivisionWarning, DeleteSuccess, CantDeleteAdminClaim, DeleteAllSuccess, NoDeletePermission, AllAdminDeleted, AdjustBlocksSuccess, NotTrappedHere, TrappedOnCooldown, RescuePending, NonSiegeWorld, AlreadySieging, NotSiegableThere, SiegeTooFarAway, NoSiegeDefenseless, AlreadyUnderSiegePlayer, AlreadyUnderSiegeArea, NoSiegeAdminClaim, SiegeOnCooldown, SiegeAlert, SiegeConfirmed, AbandonClaimMissing, NotYourClaim, DeleteTopLevelClaim, AbandonSuccess, CantGrantThatPermission, GrantPermissionNoClaim, GrantPermissionConfirmation, ManageUniversalPermissionsInstruction, ManageOneClaimPermissionsInstruction, CollectivePublic, BuildPermission, ContainersPermission, AccessPermission, PermissionsPermission, LocationCurrentClaim, LocationAllClaims, PvPImmunityStart, SiegeNoDrop, DonateItemsInstruction, ChestFull, DonationSuccess, PlayerTooCloseForFire, TooDeepToClaim, ChestClaimConfirmation, AutomaticClaimNotification, TrustCommandAdvertisement, GoldenShovelAdvertisement, UnprotectedChestWarning, ThatPlayerPvPImmune, CantFightWhileImmune, NoDamageClaimedEntity, ShovelBasicClaimMode, RemainingBlocks, CreativeBasicsDemoAdvertisement, SurvivalBasicsDemoAdvertisement, TrappedChatKeyword, TrappedInstructions, PvPNoDrop, SiegeNoTeleport, BesiegedNoTeleport, SiegeNoContainers, PvPNoContainers, PvPImmunityEnd, NoBedPermission, NoWildernessBuckets, NoLavaNearOtherPlayer, TooFarAway, BlockNotClaimed, BlockClaimed, SiegeNoShovel, RestoreNaturePlayerInChunk, NoCreateClaimPermission, ResizeClaimTooSmall, ResizeNeedMoreBlocks, NoCreativeUnClaim, ClaimResizeSuccess, ResizeFailOverlap, ResizeStart, ResizeFailOverlapSubdivision, SubdivisionStart, CreateSubdivisionOverlap, SubdivisionSuccess, CreateClaimFailOverlap, CreateClaimFailOverlapOtherPlayer, ClaimsDisabledWorld, ClaimStart, NewClaimTooSmall, CreateClaimInsufficientBlocks, AbandonClaimAdvertisement, CreateClaimFailOverlapShort, CreateClaimSuccess, SiegeWinDoorsOpen, RescueAbortedMoved, SiegeDoorsLockedEjection, NoModifyDuringSiege, OnlyOwnersModifyClaims, NoBuildUnderSiege, NoBuildPvP, NoBuildPermission, NonSiegeMaterial, NoOwnerBuildUnderSiege, NoAccessPermission, NoContainersSiege, NoContainersPermission, OwnerNameForAdminClaims, ClaimTooSmallForEntities, TooManyEntitiesInClaim, YouHaveNoClaims, ConfirmFluidRemoval, AutoBanNotify, AdjustGroupBlocksSuccess, InvalidPermissionID, UntrustOwnerOnly, HowToClaimRegex, NoBuildOutsideClaims, PlayerOfflineTime, BuildingOutsideClaims, TrappedWontWorkHere, CommandBannedInPvP, UnclaimCleanupWarning, BuySellNotConfigured, NoTeleportPvPCombat, NoTNTDamageAboveSeaLevel, NoTNTDamageClaims, IgnoreClaimsAdvertisement
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,112 +1,120 @@
/* /*
GriefPrevention Server Plugin for Minecraft GriefPrevention Server Plugin for Minecraft
Copyright (C) 2011 Ryan Hamshire Copyright (C) 2011 Ryan Hamshire
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package me.ryanhamshire.GriefPrevention; package me.ryanhamshire.GriefPrevention;
import org.bukkit.Chunk; import org.bukkit.Chunk;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.entity.Animals; import org.bukkit.entity.Animals;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.Player; import org.bukkit.entity.Hanging;
import org.bukkit.entity.Player;
//this main thread task takes the output from the RestoreNatureProcessingTask\
//and updates the world accordingly //this main thread task takes the output from the RestoreNatureProcessingTask\
class RestoreNatureExecutionTask implements Runnable //and updates the world accordingly
{ class RestoreNatureExecutionTask implements Runnable
//results from processing thread {
//will be applied to the world //results from processing thread
private BlockSnapshot[][][] snapshots; //will be applied to the world
private BlockSnapshot[][][] snapshots;
//boundaries for changes
private int miny; //boundaries for changes
private Location lesserCorner; private int miny;
private Location greaterCorner; private Location lesserCorner;
private Location greaterCorner;
//player who should be notified about the result (will see a visualization when the restoration is complete)
private Player player; //player who should be notified about the result (will see a visualization when the restoration is complete)
private Player player;
public RestoreNatureExecutionTask(BlockSnapshot[][][] snapshots, int miny, Location lesserCorner, Location greaterCorner, Player player)
{ public RestoreNatureExecutionTask(BlockSnapshot[][][] snapshots, int miny, Location lesserCorner, Location greaterCorner, Player player)
this.snapshots = snapshots; {
this.miny = miny; this.snapshots = snapshots;
this.lesserCorner = lesserCorner; this.miny = miny;
this.greaterCorner = greaterCorner; this.lesserCorner = lesserCorner;
this.player = player; this.greaterCorner = greaterCorner;
} this.player = player;
}
@Override
public void run() @Override
{ public void run()
//apply changes to the world, but ONLY to unclaimed blocks {
//note that the edge of the results is not applied (the 1-block-wide band around the outside of the chunk) //apply changes to the world, but ONLY to unclaimed blocks
//those data were sent to the processing thread for referernce purposes, but aren't part of the area selected for restoration //note that the edge of the results is not applied (the 1-block-wide band around the outside of the chunk)
Claim cachedClaim = null; //those data were sent to the processing thread for referernce purposes, but aren't part of the area selected for restoration
for(int x = 1; x < this.snapshots.length - 1; x++) Claim cachedClaim = null;
{ for(int x = 1; x < this.snapshots.length - 1; x++)
for(int z = 1; z < this.snapshots[0][0].length; z++) {
{ for(int z = 1; z < this.snapshots[0][0].length; z++)
for(int y = this.miny; y < this.snapshots[0].length; y++) {
{ for(int y = this.miny; y < this.snapshots[0].length; y++)
BlockSnapshot blockUpdate = this.snapshots[x][y][z]; {
Block currentBlock = blockUpdate.location.getBlock(); BlockSnapshot blockUpdate = this.snapshots[x][y][z];
if(blockUpdate.typeId != currentBlock.getTypeId() || blockUpdate.data != currentBlock.getData()) Block currentBlock = blockUpdate.location.getBlock();
{ if(blockUpdate.typeId != currentBlock.getTypeId() || blockUpdate.data != currentBlock.getData())
Claim claim = GriefPrevention.instance.dataStore.getClaimAt(blockUpdate.location, false, cachedClaim); {
if(claim != null) Claim claim = GriefPrevention.instance.dataStore.getClaimAt(blockUpdate.location, false, cachedClaim);
{ if(claim != null)
cachedClaim = claim; {
break; cachedClaim = claim;
} break;
}
currentBlock.setTypeId(blockUpdate.typeId);
currentBlock.setData(blockUpdate.data); currentBlock.setTypeId(blockUpdate.typeId);
} currentBlock.setData(blockUpdate.data);
} }
} }
} }
}
//clean up any entities in the chunk, ensure no players are suffocated
Chunk chunk = this.lesserCorner.getChunk(); //clean up any entities in the chunk, ensure no players are suffocated
Entity [] entities = chunk.getEntities(); Chunk chunk = this.lesserCorner.getChunk();
for(int i = 0; i < entities.length; i++) Entity [] entities = chunk.getEntities();
{ for(int i = 0; i < entities.length; i++)
Entity entity = entities[i]; {
if(!(entity instanceof Player || entity instanceof Animals)) Entity entity = entities[i];
{ if(!(entity instanceof Player || entity instanceof Animals))
entity.remove(); {
} //hanging entities (paintings, item frames) are protected when they're in land claims
else if(!(entity instanceof Hanging) || GriefPrevention.instance.dataStore.getClaimAt(entity.getLocation(), false, null) == null)
{ {
Block feetBlock = entity.getLocation().getBlock(); //everything else is removed
feetBlock.setType(Material.AIR); entity.remove();
feetBlock.getRelative(BlockFace.UP).setType(Material.AIR); }
} }
}
//for players, always ensure there's air where the player is standing
//show visualization to player else
if(player != null) {
{ Block feetBlock = entity.getLocation().getBlock();
Claim claim = new Claim(lesserCorner, greaterCorner, "", new String[] {}, new String[] {}, new String[] {}, new String[] {}, null); feetBlock.setType(Material.AIR);
Visualization visualization = Visualization.FromClaim(claim, player.getLocation().getBlockY(), VisualizationType.RestoreNature, player.getLocation()); feetBlock.getRelative(BlockFace.UP).setType(Material.AIR);
Visualization.Apply(player, visualization); }
} }
}
} //show visualization to player who started the restoration
if(player != null)
{
Claim claim = new Claim(lesserCorner, greaterCorner, "", new String[] {}, new String[] {}, new String[] {}, new String[] {}, null);
Visualization visualization = Visualization.FromClaim(claim, player.getLocation().getBlockY(), VisualizationType.RestoreNature, player.getLocation());
Visualization.Apply(player, visualization);
}
}
}

View File

@ -1,225 +1,227 @@
/* /*
GriefPrevention Server Plugin for Minecraft GriefPrevention Server Plugin for Minecraft
Copyright (C) 2011 Ryan Hamshire Copyright (C) 2011 Ryan Hamshire
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package me.ryanhamshire.GriefPrevention; package me.ryanhamshire.GriefPrevention;
import java.util.ArrayList; import java.util.ArrayList;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
//represents a visualization sent to a player //represents a visualization sent to a player
//FEATURE: to show players visually where claim boundaries are, we send them fake block change packets //FEATURE: to show players visually where claim boundaries are, we send them fake block change packets
//the result is that those players see new blocks, but the world hasn't been changed. other players can't see the new blocks, either. //the result is that those players see new blocks, but the world hasn't been changed. other players can't see the new blocks, either.
public class Visualization public class Visualization
{ {
public ArrayList<VisualizationElement> elements = new ArrayList<VisualizationElement>(); public ArrayList<VisualizationElement> elements = new ArrayList<VisualizationElement>();
//sends a visualization to a player //sends a visualization to a player
public static void Apply(Player player, Visualization visualization) public static void Apply(Player player, Visualization visualization)
{ {
PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(player.getName()); PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(player.getName());
//if he has any current visualization, clear it first //if he has any current visualization, clear it first
if(playerData.currentVisualization != null) if(playerData.currentVisualization != null)
{ {
Visualization.Revert(player); Visualization.Revert(player);
} }
//if he's online, create a task to send him the visualization in about half a second //if he's online, create a task to send him the visualization in about half a second
if(player.isOnline()) if(player.isOnline())
{ {
GriefPrevention.instance.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, new VisualizationApplicationTask(player, playerData, visualization), 10L); GriefPrevention.instance.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, new VisualizationApplicationTask(player, playerData, visualization), 10L);
} }
} }
//reverts a visualization by sending another block change list, this time with the real world block values //reverts a visualization by sending another block change list, this time with the real world block values
public static void Revert(Player player) public static void Revert(Player player)
{ {
PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(player.getName()); PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(player.getName());
Visualization visualization = playerData.currentVisualization; Visualization visualization = playerData.currentVisualization;
if(playerData.currentVisualization != null) if(playerData.currentVisualization != null)
{ {
if(player.isOnline()) if(player.isOnline())
{ {
for(int i = 0; i < visualization.elements.size(); i++) for(int i = 0; i < visualization.elements.size(); i++)
{ {
VisualizationElement element = visualization.elements.get(i); VisualizationElement element = visualization.elements.get(i);
Block block = element.location.getBlock(); Block block = element.location.getBlock();
player.sendBlockChange(element.location, block.getType(), block.getData()); player.sendBlockChange(element.location, block.getType(), block.getData());
} }
} }
playerData.currentVisualization = null; playerData.currentVisualization = null;
} }
} }
//convenience method to build a visualization from a claim //convenience method to build a visualization from a claim
//visualizationType determines the style (gold blocks, silver, red, diamond, etc) //visualizationType determines the style (gold blocks, silver, red, diamond, etc)
public static Visualization FromClaim(Claim claim, int height, VisualizationType visualizationType, Location locality) public static Visualization FromClaim(Claim claim, int height, VisualizationType visualizationType, Location locality)
{ {
//visualize only top level claims //visualize only top level claims
if(claim.parent != null) if(claim.parent != null)
{ {
return FromClaim(claim.parent, height, visualizationType, locality); return FromClaim(claim.parent, height, visualizationType, locality);
} }
Visualization visualization = new Visualization(); Visualization visualization = new Visualization();
//add subdivisions first //add subdivisions first
for(int i = 0; i < claim.children.size(); i++) for(int i = 0; i < claim.children.size(); i++)
{ {
visualization.addClaimElements(claim.children.get(i), height, VisualizationType.Subdivision, locality); visualization.addClaimElements(claim.children.get(i), height, VisualizationType.Subdivision, locality);
} }
//add top level last so that it takes precedence (it shows on top when the child claim boundaries overlap with its boundaries) //add top level last so that it takes precedence (it shows on top when the child claim boundaries overlap with its boundaries)
visualization.addClaimElements(claim, height, visualizationType, locality); visualization.addClaimElements(claim, height, visualizationType, locality);
return visualization; return visualization;
} }
//adds a claim's visualization to the current visualization //adds a claim's visualization to the current visualization
//handy for combining several visualizations together, as when visualization a top level claim with several subdivisions inside //handy for combining several visualizations together, as when visualization a top level claim with several subdivisions inside
//locality is a performance consideration. only create visualization blocks for around 100 blocks of the locality //locality is a performance consideration. only create visualization blocks for around 100 blocks of the locality
private void addClaimElements(Claim claim, int height, VisualizationType visualizationType, Location locality) private void addClaimElements(Claim claim, int height, VisualizationType visualizationType, Location locality)
{ {
Location smallXsmallZ = claim.getLesserBoundaryCorner(); Location smallXsmallZ = claim.getLesserBoundaryCorner();
Location bigXbigZ = claim.getGreaterBoundaryCorner(); Location bigXbigZ = claim.getGreaterBoundaryCorner();
World world = smallXsmallZ.getWorld(); World world = smallXsmallZ.getWorld();
int smallx = smallXsmallZ.getBlockX(); int smallx = smallXsmallZ.getBlockX();
int smallz = smallXsmallZ.getBlockZ(); int smallz = smallXsmallZ.getBlockZ();
int bigx = bigXbigZ.getBlockX(); int bigx = bigXbigZ.getBlockX();
int bigz = bigXbigZ.getBlockZ(); int bigz = bigXbigZ.getBlockZ();
Material cornerMaterial; Material cornerMaterial;
Material accentMaterial; Material accentMaterial;
if(visualizationType == VisualizationType.Claim) if(visualizationType == VisualizationType.Claim)
{ {
cornerMaterial = Material.GLOWSTONE; cornerMaterial = Material.GLOWSTONE;
accentMaterial = Material.GOLD_BLOCK; accentMaterial = Material.GOLD_BLOCK;
} }
else if(visualizationType == VisualizationType.Subdivision) else if(visualizationType == VisualizationType.Subdivision)
{ {
cornerMaterial = Material.IRON_BLOCK; cornerMaterial = Material.IRON_BLOCK;
accentMaterial = Material.WOOL; accentMaterial = Material.WOOL;
} }
else if(visualizationType == VisualizationType.RestoreNature) else if(visualizationType == VisualizationType.RestoreNature)
{ {
cornerMaterial = Material.DIAMOND_BLOCK; cornerMaterial = Material.DIAMOND_BLOCK;
accentMaterial = Material.DIAMOND_BLOCK; accentMaterial = Material.DIAMOND_BLOCK;
} }
else else
{ {
cornerMaterial = Material.GLOWING_REDSTONE_ORE; cornerMaterial = Material.GLOWING_REDSTONE_ORE;
accentMaterial = Material.NETHERRACK; accentMaterial = Material.NETHERRACK;
} }
//bottom left corner //bottom left corner
this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx, height, smallz), cornerMaterial, (byte)0)); this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx, height, smallz), cornerMaterial, (byte)0));
this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx + 1, height, smallz), accentMaterial, (byte)0)); this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx + 1, height, smallz), accentMaterial, (byte)0));
this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx, height, smallz + 1), accentMaterial, (byte)0)); this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx, height, smallz + 1), accentMaterial, (byte)0));
//bottom right corner //bottom right corner
this.elements.add(new VisualizationElement(getVisibleLocation(world, bigx, height, smallz), cornerMaterial, (byte)0)); this.elements.add(new VisualizationElement(getVisibleLocation(world, bigx, height, smallz), cornerMaterial, (byte)0));
this.elements.add(new VisualizationElement(getVisibleLocation(world, bigx - 1, height, smallz), accentMaterial, (byte)0)); this.elements.add(new VisualizationElement(getVisibleLocation(world, bigx - 1, height, smallz), accentMaterial, (byte)0));
this.elements.add(new VisualizationElement(getVisibleLocation(world, bigx, height, smallz + 1), accentMaterial, (byte)0)); this.elements.add(new VisualizationElement(getVisibleLocation(world, bigx, height, smallz + 1), accentMaterial, (byte)0));
//top right corner //top right corner
this.elements.add(new VisualizationElement(getVisibleLocation(world, bigx, height, bigz), cornerMaterial, (byte)0)); this.elements.add(new VisualizationElement(getVisibleLocation(world, bigx, height, bigz), cornerMaterial, (byte)0));
this.elements.add(new VisualizationElement(getVisibleLocation(world, bigx - 1, height, bigz), accentMaterial, (byte)0)); this.elements.add(new VisualizationElement(getVisibleLocation(world, bigx - 1, height, bigz), accentMaterial, (byte)0));
this.elements.add(new VisualizationElement(getVisibleLocation(world, bigx, height, bigz - 1), accentMaterial, (byte)0)); this.elements.add(new VisualizationElement(getVisibleLocation(world, bigx, height, bigz - 1), accentMaterial, (byte)0));
//top left corner //top left corner
this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx, height, bigz), cornerMaterial, (byte)0)); this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx, height, bigz), cornerMaterial, (byte)0));
this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx + 1, height, bigz), accentMaterial, (byte)0)); this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx + 1, height, bigz), accentMaterial, (byte)0));
this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx, height, bigz - 1), accentMaterial, (byte)0)); this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx, height, bigz - 1), accentMaterial, (byte)0));
//locality //locality
int minx = locality.getBlockX() - 100; int minx = locality.getBlockX() - 100;
int minz = locality.getBlockZ() - 100; int minz = locality.getBlockZ() - 100;
int maxx = locality.getBlockX() + 100; int maxx = locality.getBlockX() + 100;
int maxz = locality.getBlockZ() + 100; int maxz = locality.getBlockZ() + 100;
//top line //top line
for(int x = smallx + 10; x < bigx - 10; x += 10) for(int x = smallx + 10; x < bigx - 10; x += 10)
{ {
if(x > minx && x < maxx) if(x > minx && x < maxx)
this.elements.add(new VisualizationElement(getVisibleLocation(world, x, height, bigz), accentMaterial, (byte)0)); this.elements.add(new VisualizationElement(getVisibleLocation(world, x, height, bigz), accentMaterial, (byte)0));
} }
//bottom line //bottom line
for(int x = smallx + 10; x < bigx - 10; x += 10) for(int x = smallx + 10; x < bigx - 10; x += 10)
{ {
if(x > minx && x < maxx) if(x > minx && x < maxx)
this.elements.add(new VisualizationElement(getVisibleLocation(world, x, height, smallz), accentMaterial, (byte)0)); this.elements.add(new VisualizationElement(getVisibleLocation(world, x, height, smallz), accentMaterial, (byte)0));
} }
//left line //left line
for(int z = smallz + 10; z < bigz - 10; z += 10) for(int z = smallz + 10; z < bigz - 10; z += 10)
{ {
if(z > minz && z < maxz) if(z > minz && z < maxz)
this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx, height, z), accentMaterial, (byte)0)); this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx, height, z), accentMaterial, (byte)0));
} }
//right line //right line
for(int z = smallz + 10; z < bigz - 10; z += 10) for(int z = smallz + 10; z < bigz - 10; z += 10)
{ {
if(z > minz && z < maxz) if(z > minz && z < maxz)
this.elements.add(new VisualizationElement(getVisibleLocation(world, bigx, height, z), accentMaterial, (byte)0)); this.elements.add(new VisualizationElement(getVisibleLocation(world, bigx, height, z), accentMaterial, (byte)0));
} }
} }
//finds a block the player can probably see. this is how visualizations "cling" to the ground or ceiling //finds a block the player can probably see. this is how visualizations "cling" to the ground or ceiling
private static Location getVisibleLocation(World world, int x, int y, int z) private static Location getVisibleLocation(World world, int x, int y, int z)
{ {
Block block = world.getBlockAt(x, y, z); Block block = world.getBlockAt(x, y, z);
BlockFace direction = (isTransparent(block)) ? BlockFace.DOWN : BlockFace.UP; BlockFace direction = (isTransparent(block)) ? BlockFace.DOWN : BlockFace.UP;
while( block.getY() >= 1 && while( block.getY() >= 1 &&
block.getY() < world.getMaxHeight() - 1 && block.getY() < world.getMaxHeight() - 1 &&
(!isTransparent(block.getRelative(BlockFace.UP)) || isTransparent(block))) (!isTransparent(block.getRelative(BlockFace.UP)) || isTransparent(block)))
{ {
block = block.getRelative(direction); block = block.getRelative(direction);
} }
return block.getLocation(); return block.getLocation();
} }
//helper method for above. allows visualization blocks to sit underneath partly transparent blocks like grass and fence //helper method for above. allows visualization blocks to sit underneath partly transparent blocks like grass and fence
private static boolean isTransparent(Block block) private static boolean isTransparent(Block block)
{ {
return ( block.getType() == Material.AIR || return ( block.getType() == Material.AIR ||
block.getType() == Material.LONG_GRASS || block.getType() == Material.LONG_GRASS ||
block.getType() == Material.FENCE || block.getType() == Material.FENCE ||
block.getType() == Material.LEAVES || block.getType() == Material.LEAVES ||
block.getType() == Material.RED_ROSE || block.getType() == Material.RED_ROSE ||
block.getType() == Material.CHEST || block.getType() == Material.CHEST ||
block.getType() == Material.YELLOW_FLOWER ); block.getType() == Material.TORCH ||
} block.getType() == Material.VINE ||
} block.getType() == Material.YELLOW_FLOWER );
}
}