This commit is contained in:
ryanhamshire 2013-01-24 19:45:39 -08:00
parent 6fa1b7340c
commit 2734ba1ae9
9 changed files with 1728 additions and 1613 deletions

View File

@ -2,7 +2,7 @@ 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: 7.2 version: 7.2.2
commands: commands:
abandonclaim: abandonclaim:
description: Deletes a claim. description: Deletes a claim.

File diff suppressed because it is too large Load Diff

View File

@ -20,6 +20,7 @@ package me.ryanhamshire.GriefPrevention;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.FileConfiguration;
@ -31,10 +32,10 @@ import org.bukkit.inventory.ItemStack;
public abstract class DataStore public abstract class DataStore
{ {
//in-memory cache for player data //in-memory cache for player data
protected HashMap<String, PlayerData> playerNameToPlayerDataMap = new HashMap<String, PlayerData>(); protected ConcurrentHashMap<String, PlayerData> playerNameToPlayerDataMap = new ConcurrentHashMap<String, PlayerData>();
//in-memory cache for group (permission-based) data //in-memory cache for group (permission-based) data
protected HashMap<String, Integer> permissionToBonusBlocksMap = new HashMap<String, Integer>(); protected ConcurrentHashMap<String, Integer> permissionToBonusBlocksMap = new ConcurrentHashMap<String, Integer>();
//in-memory cache for claim data //in-memory cache for claim data
ArrayList<Claim> claims = new ArrayList<Claim>(); ArrayList<Claim> claims = new ArrayList<Claim>();

View File

@ -62,13 +62,7 @@ public class DatabaseDataStore extends DataStore
try try
{ {
//set username/pass properties this.refreshDataConnection();
Properties connectionProps = new Properties();
connectionProps.put("user", this.userName);
connectionProps.put("password", this.password);
//establish connection
this.databaseConnection = DriverManager.getConnection(this.databaseUrl, connectionProps);
} }
catch(Exception e2) catch(Exception e2)
{ {
@ -240,6 +234,8 @@ public class DatabaseDataStore extends DataStore
{ {
try try
{ {
this.refreshDataConnection();
//wipe out any existing data about this claim //wipe out any existing data about this claim
this.deleteClaimFromSecondaryStorage(claim); this.deleteClaimFromSecondaryStorage(claim);
@ -320,6 +316,8 @@ public class DatabaseDataStore extends DataStore
try try
{ {
this.refreshDataConnection();
Statement statement = databaseConnection.createStatement(); Statement statement = databaseConnection.createStatement();
statement.execute("INSERT INTO griefprevention_claimdata VALUES(" + statement.execute("INSERT INTO griefprevention_claimdata VALUES(" +
id + ", '" + id + ", '" +
@ -346,6 +344,8 @@ public class DatabaseDataStore extends DataStore
{ {
try try
{ {
this.refreshDataConnection();
Statement statement = this.databaseConnection.createStatement(); Statement statement = this.databaseConnection.createStatement();
statement.execute("DELETE FROM griefprevention_claimdata WHERE id=" + claim.id + ";"); statement.execute("DELETE FROM griefprevention_claimdata WHERE id=" + claim.id + ";");
statement.execute("DELETE FROM griefprevention_claimdata WHERE parentid=" + claim.id + ";"); statement.execute("DELETE FROM griefprevention_claimdata WHERE parentid=" + claim.id + ";");
@ -365,6 +365,8 @@ public class DatabaseDataStore extends DataStore
try try
{ {
this.refreshDataConnection();
Statement statement = this.databaseConnection.createStatement(); Statement statement = this.databaseConnection.createStatement();
ResultSet results = statement.executeQuery("SELECT * FROM griefprevention_playerdata WHERE name='" + playerName + "';"); ResultSet results = statement.executeQuery("SELECT * FROM griefprevention_playerdata WHERE name='" + playerName + "';");
@ -400,6 +402,8 @@ public class DatabaseDataStore extends DataStore
try try
{ {
this.refreshDataConnection();
SimpleDateFormat sqlFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); SimpleDateFormat sqlFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = sqlFormat.format(playerData.lastLogin); String dateString = sqlFormat.format(playerData.lastLogin);
@ -427,6 +431,8 @@ public class DatabaseDataStore extends DataStore
try try
{ {
this.refreshDataConnection();
Statement statement = databaseConnection.createStatement(); Statement statement = databaseConnection.createStatement();
statement.execute("DELETE FROM griefprevention_nextclaimid;"); statement.execute("DELETE FROM griefprevention_nextclaimid;");
statement.execute("INSERT INTO griefprevention_nextclaimid VALUES (" + nextID + ");"); statement.execute("INSERT INTO griefprevention_nextclaimid VALUES (" + nextID + ");");
@ -457,11 +463,28 @@ public class DatabaseDataStore extends DataStore
{ {
try try
{ {
this.databaseConnection.close(); if(!this.databaseConnection.isClosed())
{
this.databaseConnection.close();
}
} }
catch(SQLException e){}; catch(SQLException e){};
}
this.databaseConnection = null;
}
private void refreshDataConnection() throws SQLException
{
if(this.databaseConnection == null || this.databaseConnection.isClosed())
{
//set username/pass properties
Properties connectionProps = new Properties();
connectionProps.put("user", this.userName);
connectionProps.put("password", this.password);
this.databaseConnection = null; //establish connection
this.databaseConnection = DriverManager.getConnection(this.databaseUrl, connectionProps);
} }
} }
} }

View File

@ -2254,8 +2254,8 @@ public class GriefPrevention extends JavaPlugin
if(hasLeaves) if(hasLeaves)
{ {
//schedule a cleanup task for later, in case the player leaves part of this tree hanging in the air //schedule a cleanup task for later, in case the player leaves part of this tree hanging in the air
TreeCleanupTask cleanupTask = new TreeCleanupTask(block, rootBlock, treeBlocks); TreeCleanupTask cleanupTask = new TreeCleanupTask(block, rootBlock, treeBlocks, rootBlock.getData());
//20L ~ 1 second, so 2 mins = 120 seconds ~ 2400L //20L ~ 1 second, so 2 mins = 120 seconds ~ 2400L
GriefPrevention.instance.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, cleanupTask, 2400L); GriefPrevention.instance.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, cleanupTask, 2400L);
} }

View File

@ -235,15 +235,18 @@ class PlayerEventHandler implements Listener
//log entry //log entry
GriefPrevention.AddLogEntry("Banning " + player.getName() + " for spam."); GriefPrevention.AddLogEntry("Banning " + player.getName() + " for spam.");
//ban //kick and ban
GriefPrevention.instance.getServer().getOfflinePlayer(player.getName()).setBanned(true); PlayerKickBanTask task = new PlayerKickBanTask(player, GriefPrevention.instance.config_spam_banMessage);
GriefPrevention.instance.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, task, 1L);
//kick }
player.kickPlayer(GriefPrevention.instance.config_spam_banMessage);
}
else else
{ {
player.kickPlayer(""); //log entry
GriefPrevention.AddLogEntry("Banning " + player.getName() + " for spam.");
//just kick
PlayerKickBanTask task = new PlayerKickBanTask(player, null);
GriefPrevention.instance.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, task, 1L);
} }
return true; return true;

View File

@ -0,0 +1,59 @@
/*
GriefPrevention Server Plugin for Minecraft
Copyright (C) 2012 Ryan Hamshire
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
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package me.ryanhamshire.GriefPrevention;
import org.bukkit.entity.Player;
//kicks or bans a player
//need a task for this because async threads (like the chat event handlers) can't kick or ban.
//but they CAN schedule a task to run in the main thread to do that job
class PlayerKickBanTask implements Runnable
{
//player to kick or ban
private Player player;
//ban message. if null, don't ban
private String banReason;
public PlayerKickBanTask(Player player, String banReason)
{
this.player = player;
this.banReason = banReason;
}
@Override
public void run()
{
if(this.banReason != null)
{
//ban
GriefPrevention.instance.getServer().getOfflinePlayer(this.player.getName()).setBanned(true);
//kick
if(this.player.isOnline())
{
this.player.kickPlayer(this.banReason);
}
}
else if(this.player.isOnline())
{
this.player.kickPlayer("");
}
}
}

View File

@ -1,100 +1,102 @@
/* /*
GriefPrevention Server Plugin for Minecraft GriefPrevention Server Plugin for Minecraft
Copyright (C) 2012 Ryan Hamshire Copyright (C) 2012 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.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;
//FEATURE: treetops left unnaturally hanging will be automatically cleaned up //FEATURE: treetops left unnaturally hanging will be automatically cleaned up
//this main thread task revisits the location of a partially chopped tree from several minutes ago //this main thread task revisits the location of a partially chopped tree from several minutes ago
//if any part of the tree is still there and nothing else has been built in its place, remove the remaining parts //if any part of the tree is still there and nothing else has been built in its place, remove the remaining parts
class TreeCleanupTask implements Runnable class TreeCleanupTask implements Runnable
{ {
private Block originalChoppedBlock; //first block chopped in the tree private Block originalChoppedBlock; //first block chopped in the tree
private Block originalRootBlock; //where the root of the tree used to be private Block originalRootBlock; //where the root of the tree used to be
private ArrayList<Block> originalTreeBlocks; //a list of other log blocks determined to be part of this tree private byte originalRootBlockData; //data value of that root block (TYPE of log)
private ArrayList<Block> originalTreeBlocks; //a list of other log blocks determined to be part of this tree
public TreeCleanupTask(Block originalChoppedBlock, Block originalRootBlock, ArrayList<Block> originalTreeBlocks)
{ public TreeCleanupTask(Block originalChoppedBlock, Block originalRootBlock, ArrayList<Block> originalTreeBlocks, byte originalRootBlockData)
this.originalChoppedBlock = originalChoppedBlock; {
this.originalRootBlock = originalRootBlock; this.originalChoppedBlock = originalChoppedBlock;
this.originalTreeBlocks = originalTreeBlocks; this.originalRootBlock = originalRootBlock;
} this.originalTreeBlocks = originalTreeBlocks;
this.originalRootBlockData = originalRootBlockData;
@Override }
public void run()
{ @Override
//if this chunk is no longer loaded, load it and come back in a few seconds public void run()
Chunk chunk = this.originalChoppedBlock.getWorld().getChunkAt(this.originalChoppedBlock); {
if(!chunk.isLoaded()) //if this chunk is no longer loaded, load it and come back in a few seconds
{ Chunk chunk = this.originalChoppedBlock.getWorld().getChunkAt(this.originalChoppedBlock);
chunk.load(); if(!chunk.isLoaded())
GriefPrevention.instance.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, this, 100L); {
return; chunk.load();
} GriefPrevention.instance.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, this, 100L);
return;
//if the block originally chopped has been replaced with anything but air, something has been built (or has grown here) }
//in that case, don't do any cleanup
if(this.originalChoppedBlock.getWorld().getBlockAt(this.originalChoppedBlock.getLocation()).getType() != Material.AIR) return; //if the block originally chopped has been replaced with anything but air, something has been built (or has grown here)
//in that case, don't do any cleanup
//scan the original tree block locations to see if any of them have been replaced if(this.originalChoppedBlock.getWorld().getBlockAt(this.originalChoppedBlock.getLocation()).getType() != Material.AIR) return;
for(int i = 0; i < this.originalTreeBlocks.size(); i++)
{ //scan the original tree block locations to see if any of them have been replaced
Location location = this.originalTreeBlocks.get(i).getLocation(); for(int i = 0; i < this.originalTreeBlocks.size(); i++)
Block currentBlock = location.getBlock(); {
Location location = this.originalTreeBlocks.get(i).getLocation();
//if the block has been replaced, stop here, we won't do any cleanup Block currentBlock = location.getBlock();
if(currentBlock.getType() != Material.LOG && currentBlock.getType() != Material.AIR)
{ //if the block has been replaced, stop here, we won't do any cleanup
return; if(currentBlock.getType() != Material.LOG && currentBlock.getType() != Material.AIR)
} {
} return;
}
//otherwise scan again, this time removing any remaining log blocks }
boolean logsRemaining = false;
for(int i = 0; i < this.originalTreeBlocks.size(); i++) //otherwise scan again, this time removing any remaining log blocks
{ boolean logsRemaining = false;
Location location = this.originalTreeBlocks.get(i).getLocation(); for(int i = 0; i < this.originalTreeBlocks.size(); i++)
Block currentBlock = location.getBlock(); {
if(currentBlock.getType() == Material.LOG) Location location = this.originalTreeBlocks.get(i).getLocation();
{ Block currentBlock = location.getBlock();
logsRemaining = true; if(currentBlock.getType() == Material.LOG)
currentBlock.setType(Material.AIR); {
} logsRemaining = true;
} currentBlock.setType(Material.AIR);
}
//if any were actually removed and we're set to automatically replant griefed trees, place a sapling where the root block was previously }
if(logsRemaining && GriefPrevention.instance.config_trees_regrowGriefedTrees)
{ //if any were actually removed and we're set to automatically replant griefed trees, place a sapling where the root block was previously
Block currentBlock = this.originalRootBlock.getLocation().getBlock(); if(logsRemaining && GriefPrevention.instance.config_trees_regrowGriefedTrees)
//make sure there's grass or dirt underneath {
if(currentBlock.getType() == Material.AIR && (currentBlock.getRelative(BlockFace.DOWN).getType() == Material.DIRT || currentBlock.getRelative(BlockFace.DOWN).getType() == Material.GRASS)) Block currentBlock = this.originalRootBlock.getLocation().getBlock();
{ //make sure there's grass or dirt underneath
currentBlock.setType(Material.SAPLING); if(currentBlock.getType() == Material.AIR && (currentBlock.getRelative(BlockFace.DOWN).getType() == Material.DIRT || currentBlock.getRelative(BlockFace.DOWN).getType() == Material.GRASS))
currentBlock.setData(this.originalRootBlock.getData()); //makes the sapling type match the original tree type {
} currentBlock.setType(Material.SAPLING);
} currentBlock.setData(this.originalRootBlockData); //makes the sapling type match the original tree type
} }
} }
}
}