mirror of
https://github.com/taoneill/war.git
synced 2025-01-07 00:08:25 +01:00
Merge pull request #718 from taoneill/nimitz-v2
Optimize nimitz file store Tested on bukkit server 1.7.2 with a warzone originally created with war 1.7.4, therefore upgrade works properly.
This commit is contained in:
commit
59779eb0e5
@ -7,7 +7,6 @@ import java.util.*;
|
|||||||
import java.util.logging.FileHandler;
|
import java.util.logging.FileHandler;
|
||||||
import java.util.logging.Formatter;
|
import java.util.logging.Formatter;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
@ -116,16 +115,16 @@ public class War extends JavaPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see JavaPlugin.onEnable()
|
* @see JavaPlugin#onEnable()
|
||||||
* @see War.loadWar()
|
* @see War#loadWar()
|
||||||
*/
|
*/
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
this.loadWar();
|
this.loadWar();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see JavaPlugin.onDisable()
|
* @see JavaPlugin#onDisable()
|
||||||
* @see War.unloadWar()
|
* @see War#unloadWar()
|
||||||
*/
|
*/
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
this.unloadWar();
|
this.unloadWar();
|
||||||
@ -207,6 +206,7 @@ public class War extends JavaPlugin {
|
|||||||
warzoneDefaultConfig.put(WarzoneConfig.XPKILLMETER, false);
|
warzoneDefaultConfig.put(WarzoneConfig.XPKILLMETER, false);
|
||||||
warzoneDefaultConfig.put(WarzoneConfig.SOUPHEALING, false);
|
warzoneDefaultConfig.put(WarzoneConfig.SOUPHEALING, false);
|
||||||
warzoneDefaultConfig.put(WarzoneConfig.ALLOWENDER, true);
|
warzoneDefaultConfig.put(WarzoneConfig.ALLOWENDER, true);
|
||||||
|
warzoneDefaultConfig.put(WarzoneConfig.RESETBLOCKS, true);
|
||||||
|
|
||||||
teamDefaultConfig.put(TeamConfig.FLAGMUSTBEHOME, true);
|
teamDefaultConfig.put(TeamConfig.FLAGMUSTBEHOME, true);
|
||||||
teamDefaultConfig.put(TeamConfig.FLAGPOINTSONLY, false);
|
teamDefaultConfig.put(TeamConfig.FLAGPOINTSONLY, false);
|
||||||
@ -342,7 +342,7 @@ public class War extends JavaPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see JavaPlugin.onCommand()
|
* @see org.bukkit.command.CommandExecutor#onCommand(org.bukkit.command.CommandSender, org.bukkit.command.Command, String, String[])
|
||||||
*/
|
*/
|
||||||
public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
|
public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
|
||||||
return this.commandHandler.handle(sender, cmd, args);
|
return this.commandHandler.handle(sender, cmd, args);
|
||||||
@ -378,12 +378,7 @@ public class War extends JavaPlugin {
|
|||||||
loadout.put(103, inv.getHelmet().clone());
|
loadout.put(103, inv.getHelmet().clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public ItemStack copyStack(ItemStack originalStack) {
|
|
||||||
return originalStack.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void safelyEnchant(ItemStack target, Enchantment enchantment, int level) {
|
public void safelyEnchant(ItemStack target, Enchantment enchantment, int level) {
|
||||||
if (level > enchantment.getMaxLevel()) {
|
if (level > enchantment.getMaxLevel()) {
|
||||||
target.addUnsafeEnchantment(enchantment, level);
|
target.addUnsafeEnchantment(enchantment, level);
|
||||||
@ -983,10 +978,8 @@ public class War extends JavaPlugin {
|
|||||||
/**
|
/**
|
||||||
* Colors the teams and examples in messages
|
* Colors the teams and examples in messages
|
||||||
*
|
*
|
||||||
* @param String
|
* @param str message-string
|
||||||
* str message-string
|
* @param msgColor current message-color
|
||||||
* @param String
|
|
||||||
* msgColor current message-color
|
|
||||||
* @return String Message with colored teams
|
* @return String Message with colored teams
|
||||||
*/
|
*/
|
||||||
private String colorKnownTokens(String str, ChatColor msgColor) {
|
private String colorKnownTokens(String str, ChatColor msgColor) {
|
||||||
@ -1014,18 +1007,11 @@ public class War extends JavaPlugin {
|
|||||||
/**
|
/**
|
||||||
* Logs a specified message with a specified level
|
* Logs a specified message with a specified level
|
||||||
*
|
*
|
||||||
* @param String
|
* @param str message to log
|
||||||
* str message to log
|
* @param lvl level to use
|
||||||
* @param Level
|
|
||||||
* lvl level to use
|
|
||||||
*/
|
*/
|
||||||
public void log(String str, Level lvl) {
|
public void log(String str, Level lvl) {
|
||||||
// Log to Bukkit console
|
|
||||||
this.getLogger().log(lvl, str);
|
this.getLogger().log(lvl, str);
|
||||||
|
|
||||||
// if (this.warLogger != null) {
|
|
||||||
// this.warLogger.log(lvl, str);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// the only way to find a zone that has only one corner
|
// the only way to find a zone that has only one corner
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
package com.tommytony.war;
|
package com.tommytony.war;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -10,6 +14,8 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
import com.tommytony.war.mapper.VolumeMapper;
|
||||||
|
import com.tommytony.war.mapper.ZoneVolumeMapper;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.commons.lang.Validate;
|
import org.apache.commons.lang.Validate;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
@ -1028,7 +1034,11 @@ public class Warzone {
|
|||||||
} else {
|
} else {
|
||||||
// A new battle starts. Reset the zone but not the teams.
|
// A new battle starts. Reset the zone but not the teams.
|
||||||
this.broadcast("zone.battle.reset");
|
this.broadcast("zone.battle.reset");
|
||||||
this.reinitialize();
|
if (this.getWarzoneConfig().getBoolean(WarzoneConfig.RESETBLOCKS)) {
|
||||||
|
this.reinitialize();
|
||||||
|
} else {
|
||||||
|
this.initializeZone();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1146,9 +1156,10 @@ public class Warzone {
|
|||||||
team.resetPoints();
|
team.resetPoints();
|
||||||
team.setRemainingLives(team.getTeamConfig().resolveInt(TeamConfig.LIFEPOOL));
|
team.setRemainingLives(team.getTeamConfig().resolveInt(TeamConfig.LIFEPOOL));
|
||||||
}
|
}
|
||||||
this.getVolume().resetBlocksAsJob();
|
if (!this.isReinitializing()) {
|
||||||
this.initializeZoneAsJob();
|
this.reinitialize();
|
||||||
War.war.log("Last player left warzone " + this.getName() + ". Warzone blocks resetting automatically...", Level.INFO);
|
War.war.getLogger().log(Level.INFO, "Last player left warzone {0}. Warzone blocks resetting automatically...", new Object[] {this.getName()});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WarPlayerLeaveEvent event1 = new WarPlayerLeaveEvent(player.getName());
|
WarPlayerLeaveEvent event1 = new WarPlayerLeaveEvent(player.getName());
|
||||||
@ -1342,7 +1353,11 @@ public class Warzone {
|
|||||||
t.getPlayers().clear(); // empty the team
|
t.getPlayers().clear(); // empty the team
|
||||||
t.resetSign();
|
t.resetSign();
|
||||||
}
|
}
|
||||||
this.reinitialize();
|
if (this.getWarzoneConfig().getBoolean(WarzoneConfig.RESETBLOCKS)) {
|
||||||
|
this.reinitialize();
|
||||||
|
} else {
|
||||||
|
this.initializeZone();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void rewardPlayer(Player player, Map<Integer, ItemStack> reward) {
|
public void rewardPlayer(Player player, Map<Integer, ItemStack> reward) {
|
||||||
@ -1827,6 +1842,39 @@ public class Warzone {
|
|||||||
return this.getTeleport();
|
return this.getTeleport();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Volume loadStructure(String volName, World world) throws SQLException {
|
||||||
|
return loadStructure(volName, world, ZoneVolumeMapper.getZoneConnection(volume, name, world));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Volume loadStructure(String volName, Connection zoneConnection) throws SQLException {
|
||||||
|
return loadStructure(volName, world, zoneConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Volume loadStructure(String volName, World world, Connection zoneConnection) throws SQLException {
|
||||||
|
Volume volume = new Volume(volName, world);
|
||||||
|
if (!containsTable(String.format("structure_%d_corners", volName.hashCode() & Integer.MAX_VALUE), zoneConnection)) {
|
||||||
|
volume = VolumeMapper.loadVolume(volName, name, world);
|
||||||
|
ZoneVolumeMapper.saveStructure(volume, zoneConnection);
|
||||||
|
War.war.getLogger().log(Level.INFO, "Stuffed structure {0} into database for warzone {1}", new Object[] {volName, name});
|
||||||
|
return volume;
|
||||||
|
}
|
||||||
|
ZoneVolumeMapper.loadStructure(volume, zoneConnection);
|
||||||
|
return volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean containsTable(String table, Connection connection) throws SQLException {
|
||||||
|
PreparedStatement stmt = connection.prepareStatement("SELECT COUNT(*) AS ct FROM sqlite_master WHERE type = ? AND name = ?");
|
||||||
|
stmt.setString(1, "table");
|
||||||
|
stmt.setString(2, table);
|
||||||
|
ResultSet resultSet = stmt.executeQuery();
|
||||||
|
try {
|
||||||
|
return resultSet.next() && resultSet.getInt("ct") > 0;
|
||||||
|
} finally {
|
||||||
|
resultSet.close();
|
||||||
|
stmt.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a player has stolen from a warzone flag, bomb, or cake.
|
* Check if a player has stolen from a warzone flag, bomb, or cake.
|
||||||
* @param suspect Player to check.
|
* @param suspect Player to check.
|
||||||
|
@ -53,6 +53,8 @@ public class JoinCommand extends AbstractWarCommand {
|
|||||||
}
|
}
|
||||||
if (zone.getWarzoneConfig().getBoolean(WarzoneConfig.DISABLED)) {
|
if (zone.getWarzoneConfig().getBoolean(WarzoneConfig.DISABLED)) {
|
||||||
this.badMsg("join.disabled");
|
this.badMsg("join.disabled");
|
||||||
|
} else if (zone.isReinitializing()) {
|
||||||
|
this.badMsg("join.disabled");
|
||||||
} else if (zone.getWarzoneConfig().getBoolean(WarzoneConfig.AUTOASSIGN)) {
|
} else if (zone.getWarzoneConfig().getBoolean(WarzoneConfig.AUTOASSIGN)) {
|
||||||
this.badMsg("join.aarequired");
|
this.badMsg("join.aarequired");
|
||||||
} else if (!zone.getWarzoneConfig().getBoolean(WarzoneConfig.JOINMIDBATTLE) && zone.isEnoughPlayers()) {
|
} else if (!zone.getWarzoneConfig().getBoolean(WarzoneConfig.JOINMIDBATTLE) && zone.isEnoughPlayers()) {
|
||||||
|
@ -78,7 +78,7 @@ public class RenameZoneCommand extends AbstractZoneMakerCommand {
|
|||||||
|
|
||||||
// Load new warzone
|
// Load new warzone
|
||||||
War.war.log("Loading zone " + newName + "...", Level.INFO);
|
War.war.log("Loading zone " + newName + "...", Level.INFO);
|
||||||
Warzone newZone = WarzoneYmlMapper.load(newName, false);
|
Warzone newZone = WarzoneYmlMapper.load(newName);
|
||||||
War.war.getWarzones().add(newZone);
|
War.war.getWarzones().add(newZone);
|
||||||
try {
|
try {
|
||||||
newZone.getVolume().loadCorners();
|
newZone.getVolume().loadCorners();
|
||||||
|
@ -25,7 +25,8 @@ public enum WarzoneConfig {
|
|||||||
SCOREBOARD (ScoreboardType.class),
|
SCOREBOARD (ScoreboardType.class),
|
||||||
XPKILLMETER (Boolean.class),
|
XPKILLMETER (Boolean.class),
|
||||||
SOUPHEALING (Boolean.class),
|
SOUPHEALING (Boolean.class),
|
||||||
ALLOWENDER (Boolean.class);
|
ALLOWENDER (Boolean.class),
|
||||||
|
RESETBLOCKS (Boolean.class);
|
||||||
|
|
||||||
|
|
||||||
private final Class<?> configType;
|
private final Class<?> configType;
|
||||||
|
@ -20,6 +20,7 @@ import org.bukkit.event.block.Action;
|
|||||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
import org.bukkit.event.inventory.InventoryType;
|
import org.bukkit.event.inventory.InventoryType;
|
||||||
import org.bukkit.event.player.*;
|
import org.bukkit.event.player.*;
|
||||||
|
import org.bukkit.inventory.InventoryHolder;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.getspout.spoutapi.SpoutManager;
|
import org.getspout.spoutapi.SpoutManager;
|
||||||
import org.getspout.spoutapi.player.SpoutPlayer;
|
import org.getspout.spoutapi.player.SpoutPlayer;
|
||||||
@ -47,7 +48,6 @@ import java.util.logging.Level;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @author tommytony, Tim Düsterhus
|
* @author tommytony, Tim Düsterhus
|
||||||
* @package bukkit.tommytony.war
|
|
||||||
*/
|
*/
|
||||||
public class WarPlayerListener implements Listener {
|
public class WarPlayerListener implements Listener {
|
||||||
private java.util.Random random = new java.util.Random();
|
private java.util.Random random = new java.util.Random();
|
||||||
@ -56,7 +56,7 @@ public class WarPlayerListener implements Listener {
|
|||||||
/**
|
/**
|
||||||
* Correctly removes quitting players from warzones
|
* Correctly removes quitting players from warzones
|
||||||
*
|
*
|
||||||
* @see PlayerListener.onPlayerQuit()
|
* @see PlayerQuitEvent
|
||||||
*/
|
*/
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerQuit(final PlayerQuitEvent event) {
|
public void onPlayerQuit(final PlayerQuitEvent event) {
|
||||||
@ -155,7 +155,6 @@ public class WarPlayerListener implements Listener {
|
|||||||
player.getInventory().containsAtLeast(team.getKind().getBlockHead(), MINIMUM_TEAM_BLOCKS)) {
|
player.getInventory().containsAtLeast(team.getKind().getBlockHead(), MINIMUM_TEAM_BLOCKS)) {
|
||||||
// Can't pick up a second precious block
|
// Can't pick up a second precious block
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -236,20 +235,26 @@ public class WarPlayerListener implements Listener {
|
|||||||
War.war.badMsg(player, "use.ender");
|
War.war.badMsg(player, "use.ender");
|
||||||
}
|
}
|
||||||
Team team = Team.getTeamByPlayerName(player.getName());
|
Team team = Team.getTeamByPlayerName(player.getName());
|
||||||
if (team != null && event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getClickedBlock().getType() == Material.ENCHANTMENT_TABLE && team.getTeamConfig().resolveBoolean(TeamConfig.XPKILLMETER)) {
|
if (zone != null && team != null && event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getClickedBlock().getType() == Material.ENCHANTMENT_TABLE && team.getTeamConfig().resolveBoolean(TeamConfig.XPKILLMETER)) {
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
War.war.badMsg(player, "use.enchant");
|
War.war.badMsg(player, "use.enchant");
|
||||||
if (zone.getAuthors().contains(player.getName())) {
|
if (zone.getAuthors().contains(player.getName())) {
|
||||||
War.war.badMsg(player, "use.xpkillmeter");
|
War.war.badMsg(player, "use.xpkillmeter");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (team != null && event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getClickedBlock().getType() == Material.ANVIL && team.getTeamConfig().resolveBoolean(TeamConfig.XPKILLMETER)) {
|
if (zone != null && team != null && event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getClickedBlock().getType() == Material.ANVIL && team.getTeamConfig().resolveBoolean(TeamConfig.XPKILLMETER)) {
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
War.war.badMsg(player, "use.anvil");
|
War.war.badMsg(player, "use.anvil");
|
||||||
if (zone.getAuthors().contains(player.getName())) {
|
if (zone.getAuthors().contains(player.getName())) {
|
||||||
War.war.badMsg(player, "use.xpkillmeter");
|
War.war.badMsg(player, "use.xpkillmeter");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (zone != null && team != null && event.getAction() == Action.RIGHT_CLICK_BLOCK
|
||||||
|
&& event.getClickedBlock().getState() instanceof InventoryHolder
|
||||||
|
&& zone.isFlagThief(player.getName())) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
War.war.badMsg(player, "drop.flag.disabled");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.getAction() == Action.RIGHT_CLICK_BLOCK
|
if (event.getAction() == Action.RIGHT_CLICK_BLOCK
|
||||||
@ -337,7 +342,7 @@ public class WarPlayerListener implements Listener {
|
|||||||
if (locLobby != null && currentTeam == null && locLobby.isInAnyGate(playerLoc)) {
|
if (locLobby != null && currentTeam == null && locLobby.isInAnyGate(playerLoc)) {
|
||||||
Warzone zone = locLobby.getZone();
|
Warzone zone = locLobby.getZone();
|
||||||
Team locTeamGate = locLobby.getTeamGate(playerLoc);
|
Team locTeamGate = locLobby.getTeamGate(playerLoc);
|
||||||
if (zone.getWarzoneConfig().getBoolean(WarzoneConfig.DISABLED)) {
|
if (zone.getWarzoneConfig().getBoolean(WarzoneConfig.DISABLED) || zone.isReinitializing()) {
|
||||||
War.war.badMsg(player, "join.disabled");
|
War.war.badMsg(player, "join.disabled");
|
||||||
event.setTo(zone.getTeleport());
|
event.setTo(zone.getTeleport());
|
||||||
} else if (!zone.getWarzoneConfig().getBoolean(WarzoneConfig.JOINMIDBATTLE) && zone.isEnoughPlayers()) {
|
} else if (!zone.getWarzoneConfig().getBoolean(WarzoneConfig.JOINMIDBATTLE) && zone.isEnoughPlayers()) {
|
||||||
@ -376,7 +381,7 @@ public class WarPlayerListener implements Listener {
|
|||||||
if (zone != null && zone.getTeleport() != null) {
|
if (zone != null && zone.getTeleport() != null) {
|
||||||
if (zone.getWarzoneConfig().getBoolean(WarzoneConfig.AUTOJOIN)
|
if (zone.getWarzoneConfig().getBoolean(WarzoneConfig.AUTOJOIN)
|
||||||
&& zone.getTeams().size() >= 1 && currentTeam == null) {
|
&& zone.getTeams().size() >= 1 && currentTeam == null) {
|
||||||
if (zone.getWarzoneConfig().getBoolean(WarzoneConfig.DISABLED)) {
|
if (zone.getWarzoneConfig().getBoolean(WarzoneConfig.DISABLED) || zone.isReinitializing()) {
|
||||||
War.war.badMsg(player, "join.disabled");
|
War.war.badMsg(player, "join.disabled");
|
||||||
event.setTo(hub.getLocation());
|
event.setTo(hub.getLocation());
|
||||||
} else if (!zone.getWarzoneConfig().getBoolean(WarzoneConfig.JOINMIDBATTLE) && zone.isEnoughPlayers()) {
|
} else if (!zone.getWarzoneConfig().getBoolean(WarzoneConfig.JOINMIDBATTLE) && zone.isEnoughPlayers()) {
|
||||||
@ -787,7 +792,6 @@ public class WarPlayerListener implements Listener {
|
|||||||
Warzone zone = Warzone.getZoneByLocation(playerLoc);
|
Warzone zone = Warzone.getZoneByLocation(playerLoc);
|
||||||
event.setTo(zone.getTeleport());
|
event.setTo(zone.getTeleport());
|
||||||
War.war.badMsg(player, "zone.noteamnotice");
|
War.war.badMsg(player, "zone.noteamnotice");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -803,18 +807,14 @@ public class WarPlayerListener implements Listener {
|
|||||||
List<Loadout> loadouts = new ArrayList<Loadout>(playerTeam.getInventories().resolveNewLoadouts());
|
List<Loadout> loadouts = new ArrayList<Loadout>(playerTeam.getInventories().resolveNewLoadouts());
|
||||||
for (Iterator<Loadout> it = loadouts.iterator(); it.hasNext();) {
|
for (Iterator<Loadout> it = loadouts.iterator(); it.hasNext();) {
|
||||||
Loadout ldt = it.next();
|
Loadout ldt = it.next();
|
||||||
if ("first".equals(ldt.getName())) {
|
if (ldt.getName().equals("first") ||
|
||||||
|
(ldt.requiresPermission() && !event.getPlayer().hasPermission(ldt.getPermission()))) {
|
||||||
it.remove();
|
it.remove();
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (ldt.requiresPermission() && !event.getPlayer().hasPermission(ldt.getPermission())) {
|
|
||||||
it.remove();
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int currentIndex = (selection.getSelectedIndex() + 1) % loadouts.size();
|
int currentIndex = (selection.getSelectedIndex() + 1) % loadouts.size();
|
||||||
selection.setSelectedIndex(currentIndex);
|
selection.setSelectedIndex(currentIndex);
|
||||||
|
|
||||||
playerWarzone.equipPlayerLoadoutSelection(event.getPlayer(), playerTeam, false, true);
|
playerWarzone.equipPlayerLoadoutSelection(event.getPlayer(), playerTeam, false, true);
|
||||||
} else {
|
} else {
|
||||||
War.war.badMsg(event.getPlayer(), "zone.loadout.reenter");
|
War.war.badMsg(event.getPlayer(), "zone.loadout.reenter");
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
package com.tommytony.war.job;
|
package com.tommytony.war.job;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.text.DecimalFormat;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.Collections;
|
import java.text.NumberFormat;
|
||||||
import java.util.HashMap;
|
import java.util.*;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
import com.tommytony.war.mapper.ZoneVolumeMapper;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.block.BlockState;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
@ -29,55 +33,82 @@ public class PartialZoneResetJob extends BukkitRunnable implements Cloneable {
|
|||||||
private int completed = 0;
|
private int completed = 0;
|
||||||
private final long startTime = System.currentTimeMillis();
|
private final long startTime = System.currentTimeMillis();
|
||||||
private long messageCounter = System.currentTimeMillis();
|
private long messageCounter = System.currentTimeMillis();
|
||||||
|
boolean[][][] changes;
|
||||||
public static final long MESSAGE_INTERVAL = 7500;
|
public static final long MESSAGE_INTERVAL = 7500;
|
||||||
// Ticks between job runs
|
// Ticks between job runs
|
||||||
public static final int JOB_INTERVAL = 1;
|
public static final int JOB_INTERVAL = 1;
|
||||||
|
private int totalChanges = 0;
|
||||||
|
private NumberFormat formatter = new DecimalFormat("#0.00");
|
||||||
|
private Connection conn;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset a warzone's blocks at a certain speed.
|
* Reset a warzone's blocks at a certain speed.
|
||||||
*
|
*
|
||||||
* @param volume
|
* @param zone
|
||||||
* Warzone to reset.
|
* Warzone to reset.
|
||||||
* @param speed
|
* @param speed
|
||||||
* Blocks to modify per #INTERVAL.
|
* Blocks to modify per #INTERVAL.
|
||||||
*/
|
*/
|
||||||
public PartialZoneResetJob(Warzone zone, int speed) {
|
public PartialZoneResetJob(Warzone zone, int speed) throws SQLException {
|
||||||
this.zone = zone;
|
this.zone = zone;
|
||||||
this.volume = zone.getVolume();
|
this.volume = zone.getVolume();
|
||||||
this.speed = speed;
|
this.speed = speed;
|
||||||
this.total = volume.size();
|
this.total = volume.getTotalSavedBlocks();
|
||||||
|
this.changes = new boolean[volume.getSizeX()][volume.getSizeY()][volume.getSizeZ()];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
volume.resetSection(completed, speed);
|
if (conn == null || conn.isClosed()) {
|
||||||
completed += speed;
|
conn = ZoneVolumeMapper.getZoneConnection(volume, zone.getName(), volume.getWorld());
|
||||||
if (completed < total) {
|
}
|
||||||
if (System.currentTimeMillis() - messageCounter > MESSAGE_INTERVAL) {
|
if (completed >= total) {
|
||||||
messageCounter = System.currentTimeMillis();
|
int airChanges = 0;
|
||||||
int percent = (int) (((double) completed / (double) total) * 100);
|
int minX = volume.getMinX(), minY = volume.getMinY(), minZ = volume.getMinZ();
|
||||||
long seconds = (System.currentTimeMillis() - startTime) / 1000;
|
air: for (int x = volume.getMinX(); x <= volume.getMaxX(); x++) {
|
||||||
String message = MessageFormat.format(
|
for (int y = volume.getMinY(); y <= volume.getMaxY(); y++) {
|
||||||
War.war.getString("zone.battle.resetprogress"),
|
for (int z = volume.getMinZ(); z <= volume.getMaxZ(); z++) {
|
||||||
percent, seconds);
|
int xi = x - minX, yi = y - minY, zi = z - minZ;
|
||||||
this.sendMessageToAllWarzonePlayers(message);
|
if (!changes[xi][yi][zi]) {
|
||||||
|
changes[xi][yi][zi] = true;
|
||||||
|
airChanges++;
|
||||||
|
BlockState state = volume.getWorld().getBlockAt(x, y, z).getState();
|
||||||
|
if (state.getType() != Material.AIR) {
|
||||||
|
state.setType(Material.AIR);
|
||||||
|
state.update(true, false);
|
||||||
|
}
|
||||||
|
if (airChanges >= speed) {
|
||||||
|
this.displayStatusMessage();
|
||||||
|
break air;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
totalChanges += airChanges;
|
||||||
|
if (this.doneAir()) {
|
||||||
|
String secondsAsText = formatter.format(((double)(System.currentTimeMillis() - startTime)) / 1000);
|
||||||
|
String message = MessageFormat.format(
|
||||||
|
War.war.getString("zone.battle.resetcomplete"), secondsAsText);
|
||||||
|
this.sendMessageToAllWarzonePlayers(message);
|
||||||
|
PartialZoneResetJob.setSenderToNotify(zone, null); // stop notifying for this zone
|
||||||
|
zone.initializeZone();
|
||||||
|
War.war.getLogger().log(Level.INFO, "Finished reset cycle for warzone {0} (took {1} seconds)",
|
||||||
|
new Object[]{volume.getName(), secondsAsText});
|
||||||
|
conn.close();
|
||||||
|
} else {
|
||||||
|
War.war.getServer().getScheduler().runTaskLater(War.war, this.clone(), JOB_INTERVAL);
|
||||||
}
|
}
|
||||||
War.war.getServer().getScheduler()
|
|
||||||
.runTaskLater(War.war, this.clone(), JOB_INTERVAL);
|
|
||||||
} else {
|
} else {
|
||||||
long seconds = (System.currentTimeMillis() - startTime) / 1000;
|
int solidChanges = volume.resetSection(conn, completed, speed, changes);
|
||||||
String message = MessageFormat.format(
|
completed += solidChanges;
|
||||||
War.war.getString("zone.battle.resetcomplete"), seconds);
|
totalChanges += solidChanges;
|
||||||
this.sendMessageToAllWarzonePlayers(message);
|
this.displayStatusMessage();
|
||||||
PartialZoneResetJob.setSenderToNotify(zone, null); // stop notifying for this zone
|
War.war.getServer().getScheduler().runTaskLater(War.war, this.clone(), JOB_INTERVAL);
|
||||||
zone.initializeZone();
|
|
||||||
War.war.getLogger().info(
|
|
||||||
"Finished reset cycle for warzone " + volume.getName() + " (took " + seconds + " seconds)");
|
|
||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
War.war.getLogger().log(Level.WARNING,
|
War.war.getLogger().log(Level.WARNING, "Failed to load zone during reset loop", e);
|
||||||
"Failed to load zone during reset loop", e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,6 +127,18 @@ public class PartialZoneResetJob extends BukkitRunnable implements Cloneable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void displayStatusMessage() {
|
||||||
|
if (System.currentTimeMillis() - messageCounter > MESSAGE_INTERVAL) {
|
||||||
|
String secondsAsText = formatter.format(((double)(System.currentTimeMillis() - startTime)) / 1000);
|
||||||
|
messageCounter = System.currentTimeMillis();
|
||||||
|
int percent = (int) (((double) totalChanges / (double) volume.size()) * 100);
|
||||||
|
String message = MessageFormat.format(
|
||||||
|
War.war.getString("zone.battle.resetprogress"),
|
||||||
|
percent, secondsAsText);
|
||||||
|
this.sendMessageToAllWarzonePlayers(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected PartialZoneResetJob clone() {
|
protected PartialZoneResetJob clone() {
|
||||||
try {
|
try {
|
||||||
@ -108,4 +151,19 @@ public class PartialZoneResetJob extends BukkitRunnable implements Cloneable {
|
|||||||
public static void setSenderToNotify(Warzone warzone, CommandSender sender) {
|
public static void setSenderToNotify(Warzone warzone, CommandSender sender) {
|
||||||
PartialZoneResetJob.sendersToNotify.put(warzone, sender);
|
PartialZoneResetJob.sendersToNotify.put(warzone, sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean doneAir() {
|
||||||
|
int minX = volume.getMinX(), minY = volume.getMinY(), minZ = volume.getMinZ();
|
||||||
|
for (int x = volume.getMinX(); x <= volume.getMaxX(); x++) {
|
||||||
|
for (int y = volume.getMinY(); y <= volume.getMaxY(); y++) {
|
||||||
|
for (int z = volume.getMinZ(); z <= volume.getMaxZ(); z++) {
|
||||||
|
int xi = x - minX, yi = y - minY, zi = z - minZ;
|
||||||
|
if (!changes[xi][yi][zi]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,11 +12,9 @@ import com.tommytony.war.mapper.WarzoneYmlMapper;
|
|||||||
public class RestoreYmlWarzonesJob implements Runnable {
|
public class RestoreYmlWarzonesJob implements Runnable {
|
||||||
|
|
||||||
private final List<String> warzones;
|
private final List<String> warzones;
|
||||||
private final boolean newWarInstall;
|
|
||||||
|
|
||||||
public RestoreYmlWarzonesJob(List<String> warzones, boolean newWarInstall) {
|
public RestoreYmlWarzonesJob(List<String> warzones) {
|
||||||
this.warzones = warzones;
|
this.warzones = warzones;
|
||||||
this.newWarInstall = newWarInstall;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
@ -25,7 +23,7 @@ public class RestoreYmlWarzonesJob implements Runnable {
|
|||||||
for (String warzoneName : this.warzones) {
|
for (String warzoneName : this.warzones) {
|
||||||
if (warzoneName != null && !warzoneName.equals("")) {
|
if (warzoneName != null && !warzoneName.equals("")) {
|
||||||
War.war.log("Loading zone " + warzoneName + "...", Level.INFO);
|
War.war.log("Loading zone " + warzoneName + "...", Level.INFO);
|
||||||
Warzone zone = WarzoneYmlMapper.load(warzoneName, !this.newWarInstall);
|
Warzone zone = WarzoneYmlMapper.load(warzoneName);
|
||||||
if (zone != null) { // could have failed, would've been logged already
|
if (zone != null) { // could have failed, would've been logged already
|
||||||
War.war.getWarzones().add(zone);
|
War.war.getWarzones().add(zone);
|
||||||
try {
|
try {
|
||||||
|
@ -48,7 +48,7 @@ public class WarYmlMapper {
|
|||||||
|
|
||||||
// warzones
|
// warzones
|
||||||
List<String> warzones = warRootSection.getStringList("war.info.warzones");
|
List<String> warzones = warRootSection.getStringList("war.info.warzones");
|
||||||
RestoreYmlWarzonesJob restoreWarzones = new RestoreYmlWarzonesJob(warzones, newWar); // during conversion, this should execute just after the RestoreTxtWarzonesJob
|
RestoreYmlWarzonesJob restoreWarzones = new RestoreYmlWarzonesJob(warzones); // during conversion, this should execute just after the RestoreTxtWarzonesJob
|
||||||
if (War.war.getServer().getScheduler().scheduleSyncDelayedTask(War.war, restoreWarzones) == -1) {
|
if (War.war.getServer().getScheduler().scheduleSyncDelayedTask(War.war, restoreWarzones) == -1) {
|
||||||
War.war.log("Failed to schedule warzone-restore job. No warzone was loaded.", Level.WARNING);
|
War.war.log("Failed to schedule warzone-restore job. No warzone was loaded.", Level.WARNING);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package com.tommytony.war.mapper;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -32,7 +33,7 @@ import com.tommytony.war.volume.ZoneVolume;
|
|||||||
public class WarzoneYmlMapper {
|
public class WarzoneYmlMapper {
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public static Warzone load(String name, boolean createNewVolume) {
|
public static Warzone load(String name) { // removed createNewVolume, as it did nothing
|
||||||
File warzoneTxtFile = new File(War.war.getDataFolder().getPath() + "/warzone-" + name + ".txt");
|
File warzoneTxtFile = new File(War.war.getDataFolder().getPath() + "/warzone-" + name + ".txt");
|
||||||
File warzoneYmlFile = new File(War.war.getDataFolder().getPath() + "/warzone-" + name + ".yml");
|
File warzoneYmlFile = new File(War.war.getDataFolder().getPath() + "/warzone-" + name + ".yml");
|
||||||
|
|
||||||
@ -275,16 +276,16 @@ public class WarzoneYmlMapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Connection connection = null;
|
||||||
if (createNewVolume) {
|
try {
|
||||||
ZoneVolume zoneVolume = new ZoneVolume(warzone.getName(), world, warzone);
|
connection = ZoneVolumeMapper.getZoneConnection(warzone.getVolume(), warzone.getName(), warzone.getWorld());
|
||||||
warzone.setVolume(zoneVolume);
|
} catch (SQLException e) {
|
||||||
|
War.war.getLogger().log(Level.WARNING, "Failed to load warzone structures volume", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// monument blocks
|
// monument blocks
|
||||||
for (Monument monument : warzone.getMonuments()) {
|
for (Monument monument : warzone.getMonuments()) {
|
||||||
try {
|
try {
|
||||||
monument.setVolume(VolumeMapper.loadVolume(monument.getName(), warzone.getName(), world));
|
monument.setVolume(warzone.loadStructure(monument.getName(), connection));
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
War.war.getLogger().log(Level.WARNING, "Failed to load warzone structures volume", e);
|
War.war.getLogger().log(Level.WARNING, "Failed to load warzone structures volume", e);
|
||||||
}
|
}
|
||||||
@ -293,7 +294,7 @@ public class WarzoneYmlMapper {
|
|||||||
// bomb blocks
|
// bomb blocks
|
||||||
for (Bomb bomb : warzone.getBombs()) {
|
for (Bomb bomb : warzone.getBombs()) {
|
||||||
try {
|
try {
|
||||||
bomb.setVolume(VolumeMapper.loadVolume("bomb-" + bomb.getName(), warzone.getName(), world));
|
bomb.setVolume(warzone.loadStructure("bomb-" + bomb.getName(), connection));
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
War.war.getLogger().log(Level.WARNING, "Failed to load warzone structures volume", e);
|
War.war.getLogger().log(Level.WARNING, "Failed to load warzone structures volume", e);
|
||||||
}
|
}
|
||||||
@ -302,7 +303,7 @@ public class WarzoneYmlMapper {
|
|||||||
// cake blocks
|
// cake blocks
|
||||||
for (Cake cake : warzone.getCakes()) {
|
for (Cake cake : warzone.getCakes()) {
|
||||||
try {
|
try {
|
||||||
cake.setVolume(VolumeMapper.loadVolume("cake-" + cake.getName(), warzone.getName(), world));
|
cake.setVolume(warzone.loadStructure("cake-" + cake.getName(), connection));
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
War.war.getLogger().log(Level.WARNING, "Failed to load warzone structures volume", e);
|
War.war.getLogger().log(Level.WARNING, "Failed to load warzone structures volume", e);
|
||||||
}
|
}
|
||||||
@ -312,14 +313,14 @@ public class WarzoneYmlMapper {
|
|||||||
for (Team team : warzone.getTeams()) {
|
for (Team team : warzone.getTeams()) {
|
||||||
for (Location teamSpawn : team.getTeamSpawns()) {
|
for (Location teamSpawn : team.getTeamSpawns()) {
|
||||||
try {
|
try {
|
||||||
team.setSpawnVolume(teamSpawn, VolumeMapper.loadVolume(team.getName() + team.getTeamSpawns().indexOf(teamSpawn), warzone.getName(), world));
|
team.setSpawnVolume(teamSpawn, warzone.loadStructure(team.getName() + team.getTeamSpawns().indexOf(teamSpawn), connection));
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
War.war.getLogger().log(Level.WARNING, "Failed to load warzone structures volume", e);
|
War.war.getLogger().log(Level.WARNING, "Failed to load warzone structures volume", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (team.getTeamFlag() != null) {
|
if (team.getTeamFlag() != null) {
|
||||||
try {
|
try {
|
||||||
team.setFlagVolume(VolumeMapper.loadVolume(team.getName() + "flag", warzone.getName(), world));
|
team.setFlagVolume(warzone.loadStructure(team.getName() + "flag", connection));
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
War.war.getLogger().log(Level.WARNING, "Failed to load warzone structures volume", e);
|
War.war.getLogger().log(Level.WARNING, "Failed to load warzone structures volume", e);
|
||||||
}
|
}
|
||||||
@ -399,7 +400,7 @@ public class WarzoneYmlMapper {
|
|||||||
// create the lobby
|
// create the lobby
|
||||||
Volume lobbyVolume = null;
|
Volume lobbyVolume = null;
|
||||||
try {
|
try {
|
||||||
lobbyVolume = VolumeMapper.loadVolume("lobby", warzone.getName(), lobbyWorld);
|
lobbyVolume = warzone.loadStructure("lobby", lobbyWorld, connection);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
War.war.getLogger().log(Level.WARNING, "Failed to load warzone lobby", e);
|
War.war.getLogger().log(Level.WARNING, "Failed to load warzone lobby", e);
|
||||||
}
|
}
|
||||||
@ -443,7 +444,11 @@ public class WarzoneYmlMapper {
|
|||||||
(short) floorMaterialSection.getInt("data")));
|
(short) floorMaterialSection.getInt("data")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
connection.close();
|
||||||
|
} catch (SQLException ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
return warzone;
|
return warzone;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -649,11 +654,16 @@ public class WarzoneYmlMapper {
|
|||||||
flagSection.set("yaw", toIntYaw(teamFlag.getYaw()));
|
flagSection.set("yaw", toIntYaw(teamFlag.getYaw()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Connection connection = null;
|
||||||
|
try {
|
||||||
|
connection = ZoneVolumeMapper.getZoneConnection(warzone.getVolume(), warzone.getName(), warzone.getWorld());
|
||||||
|
} catch (SQLException e) {
|
||||||
|
War.war.getLogger().log(Level.WARNING, "Failed to load warzone structures volume", e);
|
||||||
|
}
|
||||||
// monument blocks
|
// monument blocks
|
||||||
for (Monument monument : warzone.getMonuments()) {
|
for (Monument monument : warzone.getMonuments()) {
|
||||||
try {
|
try {
|
||||||
VolumeMapper.save(monument.getVolume(), warzone.getName());
|
ZoneVolumeMapper.saveStructure(monument.getVolume(), connection);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
War.war.getLogger().log(Level.WARNING, "Failed to save warzone structures volume", e);
|
War.war.getLogger().log(Level.WARNING, "Failed to save warzone structures volume", e);
|
||||||
}
|
}
|
||||||
@ -662,7 +672,7 @@ public class WarzoneYmlMapper {
|
|||||||
// bomb blocks
|
// bomb blocks
|
||||||
for (Bomb bomb : warzone.getBombs()) {
|
for (Bomb bomb : warzone.getBombs()) {
|
||||||
try {
|
try {
|
||||||
VolumeMapper.save(bomb.getVolume(), warzone.getName());
|
ZoneVolumeMapper.saveStructure(bomb.getVolume(), connection);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
War.war.getLogger().log(Level.WARNING, "Failed to save warzone structures volume", e);
|
War.war.getLogger().log(Level.WARNING, "Failed to save warzone structures volume", e);
|
||||||
}
|
}
|
||||||
@ -671,7 +681,7 @@ public class WarzoneYmlMapper {
|
|||||||
// cake blocks
|
// cake blocks
|
||||||
for (Cake cake : warzone.getCakes()) {
|
for (Cake cake : warzone.getCakes()) {
|
||||||
try {
|
try {
|
||||||
VolumeMapper.save(cake.getVolume(), warzone.getName());
|
ZoneVolumeMapper.saveStructure(cake.getVolume(), connection);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
War.war.getLogger().log(Level.WARNING, "Failed to save warzone structures volume", e);
|
War.war.getLogger().log(Level.WARNING, "Failed to save warzone structures volume", e);
|
||||||
}
|
}
|
||||||
@ -681,14 +691,14 @@ public class WarzoneYmlMapper {
|
|||||||
for (Team team : teams) {
|
for (Team team : teams) {
|
||||||
for (Volume volume : team.getSpawnVolumes().values()) {
|
for (Volume volume : team.getSpawnVolumes().values()) {
|
||||||
try {
|
try {
|
||||||
VolumeMapper.save(volume, warzone.getName());
|
ZoneVolumeMapper.saveStructure(volume, connection);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
War.war.getLogger().log(Level.WARNING, "Failed to save warzone structures volume", e);
|
War.war.getLogger().log(Level.WARNING, "Failed to save warzone structures volume", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (team.getFlagVolume() != null) {
|
if (team.getFlagVolume() != null) {
|
||||||
try {
|
try {
|
||||||
VolumeMapper.save(team.getFlagVolume(), warzone.getName());
|
ZoneVolumeMapper.saveStructure(team.getFlagVolume(), connection);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
War.war.getLogger().log(Level.WARNING, "Failed to save warzone structures volume", e);
|
War.war.getLogger().log(Level.WARNING, "Failed to save warzone structures volume", e);
|
||||||
}
|
}
|
||||||
@ -697,12 +707,16 @@ public class WarzoneYmlMapper {
|
|||||||
|
|
||||||
if (warzone.getLobby() != null) {
|
if (warzone.getLobby() != null) {
|
||||||
try {
|
try {
|
||||||
VolumeMapper.save(warzone.getLobby().getVolume(), warzone.getName());
|
ZoneVolumeMapper.saveStructure(warzone.getLobby().getVolume(), connection);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
War.war.getLogger().log(Level.WARNING, "Failed to save warzone structures volume", e);
|
War.war.getLogger().log(Level.WARNING, "Failed to save warzone structures volume", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
connection.close();
|
||||||
|
} catch (SQLException ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
// Save to disk
|
// Save to disk
|
||||||
try {
|
try {
|
||||||
File warzoneConfigFile = new File(War.war.getDataFolder().getPath() + "/warzone-" + warzone.getName() + ".yml");
|
File warzoneConfigFile = new File(War.war.getDataFolder().getPath() + "/warzone-" + warzone.getName() + ".yml");
|
||||||
|
@ -7,7 +7,7 @@ import java.sql.PreparedStatement;
|
|||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
import java.sql.Types;
|
import java.text.DecimalFormat;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
@ -46,29 +46,23 @@ import com.tommytony.war.volume.ZoneVolume;
|
|||||||
*/
|
*/
|
||||||
public class ZoneVolumeMapper {
|
public class ZoneVolumeMapper {
|
||||||
|
|
||||||
public static final int DATABASE_VERSION = 1;
|
public static final int DATABASE_VERSION = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the given volume
|
* Get a connection to the warzone database, converting blocks if not found.
|
||||||
*
|
* @param volume zone volume to load
|
||||||
* @param ZoneVolume volume Volume to load
|
* @param zoneName warzone to load
|
||||||
* @param String zoneName Zone to load the volume from
|
* @param world world containing this warzone
|
||||||
* @param World world The world the zone is located
|
* @return an open connection to the sqlite file
|
||||||
* @param boolean onlyLoadCorners Should only the corners be loaded
|
* @throws SQLException
|
||||||
* @param start Starting position to load blocks at
|
|
||||||
* @param total Amount of blocks to read
|
|
||||||
* @return integer Changed blocks
|
|
||||||
* @throws SQLException Error communicating with SQLite3 database
|
|
||||||
*/
|
*/
|
||||||
public static int load(ZoneVolume volume, String zoneName, World world, boolean onlyLoadCorners, int start, int total) throws SQLException {
|
public static Connection getZoneConnection(ZoneVolume volume, String zoneName, World world) throws SQLException {
|
||||||
int changed = 0;
|
|
||||||
File databaseFile = new File(War.war.getDataFolder(), String.format("/dat/warzone-%s/volume-%s.sl3", zoneName, volume.getName()));
|
File databaseFile = new File(War.war.getDataFolder(), String.format("/dat/warzone-%s/volume-%s.sl3", zoneName, volume.getName()));
|
||||||
if (!databaseFile.exists()) {
|
if (!databaseFile.exists()) {
|
||||||
// Convert warzone to nimitz file format.
|
// Convert warzone to nimitz file format.
|
||||||
changed = PreNimitzZoneVolumeMapper.load(volume, zoneName, world, onlyLoadCorners);
|
PreNimitzZoneVolumeMapper.load(volume, zoneName, world, false);
|
||||||
ZoneVolumeMapper.save(volume, zoneName);
|
ZoneVolumeMapper.save(volume, zoneName);
|
||||||
War.war.log("Warzone " + zoneName + " converted to nimitz format!", Level.INFO);
|
War.war.log("Warzone " + zoneName + " converted to nimitz format!", Level.INFO);
|
||||||
return changed;
|
|
||||||
}
|
}
|
||||||
Connection databaseConnection = DriverManager.getConnection("jdbc:sqlite:" + databaseFile.getPath());
|
Connection databaseConnection = DriverManager.getConnection("jdbc:sqlite:" + databaseFile.getPath());
|
||||||
Statement stmt = databaseConnection.createStatement();
|
Statement stmt = databaseConnection.createStatement();
|
||||||
@ -76,17 +70,46 @@ public class ZoneVolumeMapper {
|
|||||||
int version = versionQuery.getInt("user_version");
|
int version = versionQuery.getInt("user_version");
|
||||||
versionQuery.close();
|
versionQuery.close();
|
||||||
if (version > DATABASE_VERSION) {
|
if (version > DATABASE_VERSION) {
|
||||||
try {
|
stmt.close();
|
||||||
throw new IllegalStateException("Unsupported zone format " + version);
|
databaseConnection.close();
|
||||||
} finally {
|
|
||||||
stmt.close();
|
// Can't load this too-recent format
|
||||||
databaseConnection.close();
|
throw new IllegalStateException(String.format("Unsupported zone format (was already converted to version: %d, current format: %d)", version, DATABASE_VERSION));
|
||||||
}
|
|
||||||
} else if (version < DATABASE_VERSION) {
|
} else if (version < DATABASE_VERSION) {
|
||||||
|
stmt.close();
|
||||||
|
|
||||||
|
// We need to migrate to newest schema
|
||||||
switch (version) {
|
switch (version) {
|
||||||
// Run some update SQL for each old version
|
// Run some update SQL for each old version
|
||||||
|
case 1:
|
||||||
|
// Run update from 1 to 2
|
||||||
|
updateFromVersionOneToTwo(zoneName, databaseConnection);
|
||||||
|
|
||||||
|
// How to continue this pattern: (@tommytony multiple in one shouldn't be needed, just don't put a break in the switch)
|
||||||
|
// case 2:
|
||||||
|
// // Run update from 2 to 3
|
||||||
|
// updateFromVersionTwoToTree(zoneName, databaseConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
return databaseConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the given volume
|
||||||
|
*
|
||||||
|
* @param databaseConnection Open connection to zone database
|
||||||
|
* @param volume Volume to load
|
||||||
|
* @param world The world the zone is located
|
||||||
|
* @param onlyLoadCorners Should only the corners be loaded
|
||||||
|
* @param start Starting position to load blocks at
|
||||||
|
* @param total Amount of blocks to read
|
||||||
|
* @return Changed blocks
|
||||||
|
* @throws SQLException Error communicating with SQLite3 database
|
||||||
|
*/
|
||||||
|
public static int load(Connection databaseConnection, ZoneVolume volume, World world, boolean onlyLoadCorners, int start, int total, boolean[][][] changes) throws SQLException {
|
||||||
|
Validate.isTrue(!databaseConnection.isClosed());
|
||||||
|
Statement stmt = databaseConnection.createStatement();
|
||||||
ResultSet cornerQuery = stmt.executeQuery("SELECT * FROM corners");
|
ResultSet cornerQuery = stmt.executeQuery("SELECT * FROM corners");
|
||||||
cornerQuery.next();
|
cornerQuery.next();
|
||||||
final Block corner1 = world.getBlockAt(cornerQuery.getInt("x"), cornerQuery.getInt("y"), cornerQuery.getInt("z"));
|
final Block corner1 = world.getBlockAt(cornerQuery.getInt("x"), cornerQuery.getInt("y"), cornerQuery.getInt("z"));
|
||||||
@ -97,69 +120,190 @@ public class ZoneVolumeMapper {
|
|||||||
volume.setCornerTwo(corner2);
|
volume.setCornerTwo(corner2);
|
||||||
if (onlyLoadCorners) {
|
if (onlyLoadCorners) {
|
||||||
stmt.close();
|
stmt.close();
|
||||||
databaseConnection.close();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
int minX = volume.getMinX(), minY = volume.getMinY(), minZ = volume.getMinZ();
|
||||||
|
int changed = 0;
|
||||||
ResultSet query = stmt.executeQuery("SELECT * FROM blocks ORDER BY rowid LIMIT " + start + ", " + total);
|
ResultSet query = stmt.executeQuery("SELECT * FROM blocks ORDER BY rowid LIMIT " + start + ", " + total);
|
||||||
while (query.next()) {
|
while (query.next()) {
|
||||||
int x = query.getInt("x"), y = query.getInt("y"), z = query.getInt("z");
|
int x = query.getInt("x"), y = query.getInt("y"), z = query.getInt("z");
|
||||||
BlockState modify = corner1.getRelative(x, y, z).getState();
|
changed++;
|
||||||
|
Block relative = corner1.getRelative(x, y, z);
|
||||||
|
int xi = relative.getX() - minX, yi = relative.getY() - minY, zi = relative.getZ() - minZ;
|
||||||
|
if (changes != null) {
|
||||||
|
changes[xi][yi][zi] = true;
|
||||||
|
}
|
||||||
|
BlockState modify = relative.getState();
|
||||||
ItemStack data = new ItemStack(Material.valueOf(query.getString("type")), 0, query.getShort("data"));
|
ItemStack data = new ItemStack(Material.valueOf(query.getString("type")), 0, query.getShort("data"));
|
||||||
modify.setType(data.getType());
|
if (modify.getType() != data.getType() || !modify.getData().equals(data.getData())) {
|
||||||
modify.setData(data.getData());
|
// Update the type & data if it has changed
|
||||||
modify.update(true, false); // No-physics update, preventing the need for deferring blocks
|
modify.setType(data.getType());
|
||||||
modify = corner1.getRelative(x, y, z).getState(); // Grab a new instance
|
modify.setData(data.getData());
|
||||||
|
modify.update(true, false); // No-physics update, preventing the need for deferring blocks
|
||||||
|
modify = corner1.getRelative(x, y, z).getState(); // Grab a new instance
|
||||||
|
}
|
||||||
|
if (query.getString("metadata") == null || query.getString("metadata").isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
if (modify instanceof Sign) {
|
if (modify instanceof Sign) {
|
||||||
final String[] lines = query.getString("sign").split("\n");
|
final String[] lines = query.getString("metadata").split("\n");
|
||||||
for (int i = 0; i < lines.length; i++) {
|
for (int i = 0; i < lines.length; i++) {
|
||||||
((Sign) modify).setLine(i, lines[i]);
|
((Sign) modify).setLine(i, lines[i]);
|
||||||
}
|
}
|
||||||
|
modify.update(true, false);
|
||||||
}
|
}
|
||||||
if (modify instanceof InventoryHolder && query.getString("container") != null) {
|
|
||||||
|
// Containers
|
||||||
|
if (modify instanceof InventoryHolder) {
|
||||||
YamlConfiguration config = new YamlConfiguration();
|
YamlConfiguration config = new YamlConfiguration();
|
||||||
config.loadFromString(query.getString("container"));
|
config.loadFromString(query.getString("metadata"));
|
||||||
((InventoryHolder) modify).getInventory().clear();
|
((InventoryHolder) modify).getInventory().clear();
|
||||||
for (Object obj : config.getList("items")) {
|
for (Object obj : config.getList("items")) {
|
||||||
if (obj instanceof ItemStack) {
|
if (obj instanceof ItemStack) {
|
||||||
((InventoryHolder) modify).getInventory().addItem((ItemStack) obj);
|
((InventoryHolder) modify).getInventory().addItem((ItemStack) obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
modify.update(true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Notes
|
||||||
if (modify instanceof NoteBlock) {
|
if (modify instanceof NoteBlock) {
|
||||||
String[] split = query.getString("note").split("\n");
|
String[] split = query.getString("metadata").split("\n");
|
||||||
Note note = new Note(Integer.parseInt(split[1]), Tone.valueOf(split[0]), Boolean.parseBoolean(split[2]));
|
Note note = new Note(Integer.parseInt(split[1]), Tone.valueOf(split[0]), Boolean.parseBoolean(split[2]));
|
||||||
((NoteBlock) modify).setNote(note);
|
((NoteBlock) modify).setNote(note);
|
||||||
|
modify.update(true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Records
|
||||||
if (modify instanceof Jukebox) {
|
if (modify instanceof Jukebox) {
|
||||||
((Jukebox) modify).setPlaying(Material.valueOf(query.getString("record")));
|
((Jukebox) modify).setPlaying(Material.valueOf(query.getString("metadata")));
|
||||||
|
modify.update(true, false);
|
||||||
}
|
}
|
||||||
if (modify instanceof Skull && query.getString("skull") != null) {
|
|
||||||
String[] opts = query.getString("skull").split("\n");
|
// Skulls
|
||||||
|
if (modify instanceof Skull) {
|
||||||
|
String[] opts = query.getString("metadata").split("\n");
|
||||||
((Skull) modify).setOwner(opts[0]);
|
((Skull) modify).setOwner(opts[0]);
|
||||||
((Skull) modify).setSkullType(SkullType.valueOf(opts[1]));
|
((Skull) modify).setSkullType(SkullType.valueOf(opts[1]));
|
||||||
((Skull) modify).setRotation(BlockFace.valueOf(opts[2]));
|
((Skull) modify).setRotation(BlockFace.valueOf(opts[2]));
|
||||||
|
modify.update(true, false);
|
||||||
}
|
}
|
||||||
if (modify instanceof CommandBlock && query.getString("command") != null) {
|
|
||||||
final String[] commandArray = query.getString("command").split("\n");
|
// Command blocks
|
||||||
|
if (modify instanceof CommandBlock) {
|
||||||
|
final String[] commandArray = query.getString("metadata").split("\n");
|
||||||
((CommandBlock) modify).setName(commandArray[0]);
|
((CommandBlock) modify).setName(commandArray[0]);
|
||||||
((CommandBlock) modify).setCommand(commandArray[1]);
|
((CommandBlock) modify).setCommand(commandArray[1]);
|
||||||
|
modify.update(true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Creature spawner
|
||||||
if (modify instanceof CreatureSpawner) {
|
if (modify instanceof CreatureSpawner) {
|
||||||
((CreatureSpawner) modify).setSpawnedType(EntityType.valueOf(query.getString("mobid")));
|
((CreatureSpawner) modify).setSpawnedType(EntityType.valueOf(query.getString("metadata")));
|
||||||
|
modify.update(true, false);
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
War.war.getLogger().log(Level.WARNING, "Exception loading some tile data", ex);
|
War.war.getLogger().log(Level.WARNING, "Exception loading some tile data. x:" + x + " y:" + y + " z:" + z + " type:" + modify.getType().toString() + " data:" + modify.getData().toString(), ex);
|
||||||
}
|
}
|
||||||
modify.update(true, false);
|
|
||||||
changed++;
|
|
||||||
}
|
}
|
||||||
query.close();
|
query.close();
|
||||||
stmt.close();
|
stmt.close();
|
||||||
databaseConnection.close();
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int saveStructure(Volume volume, Connection databaseConnection) throws SQLException {
|
||||||
|
Statement stmt = databaseConnection.createStatement();
|
||||||
|
stmt.executeUpdate("PRAGMA user_version = " + DATABASE_VERSION);
|
||||||
|
// Storing zonemaker-inputted name could result in injection or undesirable behavior.
|
||||||
|
String prefix = String.format("structure_%d", volume.getName().hashCode() & Integer.MAX_VALUE);
|
||||||
|
stmt.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix +
|
||||||
|
"_blocks (x BIGINT, y BIGINT, z BIGINT, type TEXT, data SMALLINT)");
|
||||||
|
stmt.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix +
|
||||||
|
"_corners (pos INTEGER PRIMARY KEY NOT NULL UNIQUE, x INTEGER NOT NULL, y INTEGER NOT NULL, z INTEGER NOT NULL)");
|
||||||
|
stmt.executeUpdate("DELETE FROM " + prefix + "_blocks");
|
||||||
|
stmt.executeUpdate("DELETE FROM " + prefix + "_corners");
|
||||||
|
stmt.close();
|
||||||
|
PreparedStatement cornerStmt = databaseConnection
|
||||||
|
.prepareStatement("INSERT INTO " + prefix + "_corners SELECT 1 AS pos, ? AS x, ? AS y, ? AS z UNION SELECT 2, ?, ?, ?");
|
||||||
|
cornerStmt.setInt(1, volume.getCornerOne().getBlockX());
|
||||||
|
cornerStmt.setInt(2, volume.getCornerOne().getBlockY());
|
||||||
|
cornerStmt.setInt(3, volume.getCornerOne().getBlockZ());
|
||||||
|
cornerStmt.setInt(4, volume.getCornerTwo().getBlockX());
|
||||||
|
cornerStmt.setInt(5, volume.getCornerTwo().getBlockY());
|
||||||
|
cornerStmt.setInt(6, volume.getCornerTwo().getBlockZ());
|
||||||
|
cornerStmt.executeUpdate();
|
||||||
|
cornerStmt.close();
|
||||||
|
PreparedStatement dataStmt = databaseConnection
|
||||||
|
.prepareStatement("INSERT INTO " + prefix + "_blocks VALUES (?, ?, ?, ?, ?)");
|
||||||
|
databaseConnection.setAutoCommit(false);
|
||||||
|
final int batchSize = 1000;
|
||||||
|
int changed = 0;
|
||||||
|
for (BlockState block : volume.getBlocks()) {
|
||||||
|
final Location relLoc = ZoneVolumeMapper.rebase(
|
||||||
|
volume.getCornerOne(), block.getLocation());
|
||||||
|
dataStmt.setInt(1, relLoc.getBlockX());
|
||||||
|
dataStmt.setInt(2, relLoc.getBlockY());
|
||||||
|
dataStmt.setInt(3, relLoc.getBlockZ());
|
||||||
|
dataStmt.setString(4, block.getType().toString());
|
||||||
|
dataStmt.setShort(5, block.getData().toItemStack().getDurability());
|
||||||
|
dataStmt.addBatch();
|
||||||
|
if (++changed % batchSize == 0) {
|
||||||
|
dataStmt.executeBatch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dataStmt.executeBatch(); // insert remaining records
|
||||||
|
databaseConnection.commit();
|
||||||
|
databaseConnection.setAutoCommit(true);
|
||||||
|
dataStmt.close();
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void loadStructure(Volume volume, Connection databaseConnection) throws SQLException {
|
||||||
|
String prefix = String.format("structure_%d", volume.getName().hashCode() & Integer.MAX_VALUE);
|
||||||
|
World world = volume.getWorld();
|
||||||
|
Statement stmt = databaseConnection.createStatement();
|
||||||
|
ResultSet cornerQuery = stmt.executeQuery("SELECT * FROM " + prefix + "_corners");
|
||||||
|
cornerQuery.next();
|
||||||
|
final Block corner1 = world.getBlockAt(cornerQuery.getInt("x"), cornerQuery.getInt("y"), cornerQuery.getInt("z"));
|
||||||
|
cornerQuery.next();
|
||||||
|
final Block corner2 = world.getBlockAt(cornerQuery.getInt("x"), cornerQuery.getInt("y"), cornerQuery.getInt("z"));
|
||||||
|
cornerQuery.close();
|
||||||
|
volume.setCornerOne(corner1);
|
||||||
|
volume.setCornerTwo(corner2);
|
||||||
|
volume.getBlocks().clear();
|
||||||
|
ResultSet query = stmt.executeQuery("SELECT * FROM " + prefix + "_blocks");
|
||||||
|
while (query.next()) {
|
||||||
|
int x = query.getInt("x"), y = query.getInt("y"), z = query.getInt("z");
|
||||||
|
BlockState modify = corner1.getRelative(x, y, z).getState();
|
||||||
|
ItemStack data = new ItemStack(Material.valueOf(query.getString("type")), 0, query.getShort("data"));
|
||||||
|
modify.setType(data.getType());
|
||||||
|
modify.setData(data.getData());
|
||||||
|
volume.getBlocks().add(modify);
|
||||||
|
}
|
||||||
|
query.close();
|
||||||
|
stmt.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get total saved blocks for a warzone. This should only be called on nimitz-format warzones.
|
||||||
|
* @param volume Warzone volume
|
||||||
|
* @param zoneName Name of zone file
|
||||||
|
* @return Total saved blocks
|
||||||
|
* @throws SQLException
|
||||||
|
*/
|
||||||
|
public static int getTotalSavedBlocks(ZoneVolume volume, String zoneName) throws SQLException {
|
||||||
|
File databaseFile = new File(War.war.getDataFolder(), String.format("/dat/warzone-%s/volume-%s.sl3", zoneName, volume.getName()));
|
||||||
|
Connection databaseConnection = DriverManager.getConnection("jdbc:sqlite:" + databaseFile.getPath());
|
||||||
|
Statement stmt = databaseConnection.createStatement();
|
||||||
|
ResultSet sizeQuery = stmt.executeQuery("SELECT COUNT(*) AS total FROM blocks");
|
||||||
|
int size = sizeQuery.getInt("total");
|
||||||
|
sizeQuery.close();
|
||||||
|
stmt.close();
|
||||||
|
databaseConnection.close();
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save all war zone blocks to a SQLite3 database file.
|
* Save all war zone blocks to a SQLite3 database file.
|
||||||
*
|
*
|
||||||
@ -169,14 +313,17 @@ public class ZoneVolumeMapper {
|
|||||||
* @throws SQLException
|
* @throws SQLException
|
||||||
*/
|
*/
|
||||||
public static int save(Volume volume, String zoneName) throws SQLException {
|
public static int save(Volume volume, String zoneName) throws SQLException {
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
int changed = 0;
|
int changed = 0;
|
||||||
File warzoneDir = new File(War.war.getDataFolder().getPath() + "/dat/warzone-" + zoneName);
|
File warzoneDir = new File(War.war.getDataFolder().getPath() + "/dat/warzone-" + zoneName);
|
||||||
warzoneDir.mkdirs();
|
if (!warzoneDir.exists() && !warzoneDir.mkdirs()) {
|
||||||
|
throw new RuntimeException("Failed to create warzone data directory");
|
||||||
|
}
|
||||||
File databaseFile = new File(War.war.getDataFolder(), String.format("/dat/warzone-%s/volume-%s.sl3", zoneName, volume.getName()));
|
File databaseFile = new File(War.war.getDataFolder(), String.format("/dat/warzone-%s/volume-%s.sl3", zoneName, volume.getName()));
|
||||||
Connection databaseConnection = DriverManager.getConnection("jdbc:sqlite:" + databaseFile.getPath());
|
Connection databaseConnection = DriverManager.getConnection("jdbc:sqlite:" + databaseFile.getPath());
|
||||||
Statement stmt = databaseConnection.createStatement();
|
Statement stmt = databaseConnection.createStatement();
|
||||||
stmt.executeUpdate("PRAGMA user_version = " + DATABASE_VERSION);
|
stmt.executeUpdate("PRAGMA user_version = " + DATABASE_VERSION);
|
||||||
stmt.executeUpdate("CREATE TABLE IF NOT EXISTS blocks (x BIGINT, y BIGINT, z BIGINT, type TEXT, data SMALLINT, sign TEXT, container BLOB, note INT, record TEXT, skull TEXT, command TEXT, mobid TEXT)");
|
stmt.executeUpdate("CREATE TABLE IF NOT EXISTS blocks (x BIGINT, y BIGINT, z BIGINT, type TEXT, data SMALLINT, metadata BLOB)");
|
||||||
stmt.executeUpdate("CREATE TABLE IF NOT EXISTS corners (pos INTEGER PRIMARY KEY NOT NULL UNIQUE, x INTEGER NOT NULL, y INTEGER NOT NULL, z INTEGER NOT NULL)");
|
stmt.executeUpdate("CREATE TABLE IF NOT EXISTS corners (pos INTEGER PRIMARY KEY NOT NULL UNIQUE, x INTEGER NOT NULL, y INTEGER NOT NULL, z INTEGER NOT NULL)");
|
||||||
stmt.executeUpdate("DELETE FROM blocks");
|
stmt.executeUpdate("DELETE FROM blocks");
|
||||||
stmt.executeUpdate("DELETE FROM corners");
|
stmt.executeUpdate("DELETE FROM corners");
|
||||||
@ -190,67 +337,57 @@ public class ZoneVolumeMapper {
|
|||||||
cornerStmt.setInt(6, volume.getCornerTwo().getBlockZ());
|
cornerStmt.setInt(6, volume.getCornerTwo().getBlockZ());
|
||||||
cornerStmt.executeUpdate();
|
cornerStmt.executeUpdate();
|
||||||
cornerStmt.close();
|
cornerStmt.close();
|
||||||
PreparedStatement dataStmt = databaseConnection.prepareStatement("INSERT INTO blocks VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
PreparedStatement dataStmt = databaseConnection.prepareStatement("INSERT INTO blocks (x, y, z, type, data, metadata) VALUES (?, ?, ?, ?, ?, ?)");
|
||||||
databaseConnection.setAutoCommit(false);
|
databaseConnection.setAutoCommit(false);
|
||||||
final int batchSize = 1000;
|
final int batchSize = 10000;
|
||||||
for (int i = 0, x = volume.getMinX(); i < volume.getSizeX(); i++, x++) {
|
for (int i = 0, x = volume.getMinX(); i < volume.getSizeX(); i++, x++) {
|
||||||
for (int j = 0, y = volume.getMinY(); j < volume.getSizeY(); j++, y++) {
|
for (int j = 0, y = volume.getMinY(); j < volume.getSizeY(); j++, y++) {
|
||||||
for (int k = 0, z = volume.getMinZ(); k < volume.getSizeZ(); k++, z++) {
|
for (int k = 0, z = volume.getMinZ(); k < volume.getSizeZ(); k++, z++) {
|
||||||
|
// Make sure we are using zone volume-relative coords
|
||||||
final Block block = volume.getWorld().getBlockAt(x, y, z);
|
final Block block = volume.getWorld().getBlockAt(x, y, z);
|
||||||
final Location relLoc = rebase(volume.getCornerOne(), block.getLocation());
|
if (block.getType() == Material.AIR) {
|
||||||
dataStmt.setInt(1, relLoc.getBlockX());
|
continue; // Do not save air blocks to the file anymore.
|
||||||
dataStmt.setInt(2, relLoc.getBlockY());
|
}
|
||||||
dataStmt.setInt(3, relLoc.getBlockZ());
|
final BlockState state = block.getState();
|
||||||
dataStmt.setString(4, block.getType().toString());
|
dataStmt.setInt(1, block.getX() - volume.getCornerOne().getBlockX());
|
||||||
dataStmt.setShort(5, block.getState().getData().toItemStack().getDurability());
|
dataStmt.setInt(2, block.getY() - volume.getCornerOne().getBlockY());
|
||||||
if (block.getState() instanceof Sign) {
|
dataStmt.setInt(3, block.getZ() - volume.getCornerOne().getBlockZ());
|
||||||
|
dataStmt.setString(4, block.getType().name());
|
||||||
|
dataStmt.setShort(5, state.getData().toItemStack().getDurability());
|
||||||
|
if (state instanceof Sign) {
|
||||||
final String signText = StringUtils.join(((Sign) block.getState()).getLines(), "\n");
|
final String signText = StringUtils.join(((Sign) block.getState()).getLines(), "\n");
|
||||||
dataStmt.setString(6, signText);
|
dataStmt.setString(6, signText);
|
||||||
} else {
|
} else if (state instanceof InventoryHolder) {
|
||||||
dataStmt.setNull(6, Types.VARCHAR);
|
|
||||||
}
|
|
||||||
if (block.getState() instanceof InventoryHolder) {
|
|
||||||
List<ItemStack> items = Arrays.asList(((InventoryHolder) block.getState()).getInventory().getContents());
|
List<ItemStack> items = Arrays.asList(((InventoryHolder) block.getState()).getInventory().getContents());
|
||||||
YamlConfiguration config = new YamlConfiguration();
|
YamlConfiguration config = new YamlConfiguration();
|
||||||
// Serialize to config, then store config in database
|
// Serialize to config, then store config in database
|
||||||
config.set("items", items);
|
config.set("items", items);
|
||||||
dataStmt.setString(7, config.saveToString());
|
dataStmt.setString(6, config.saveToString());
|
||||||
} else {
|
} else if (state instanceof NoteBlock) {
|
||||||
dataStmt.setNull(7, Types.BLOB);
|
|
||||||
}
|
|
||||||
if (block.getState() instanceof NoteBlock) {
|
|
||||||
Note note = ((NoteBlock) block.getState()).getNote();
|
Note note = ((NoteBlock) block.getState()).getNote();
|
||||||
dataStmt.setString(8, note.getTone().toString() + '\n' + note.getOctave() + '\n' + note.isSharped());
|
dataStmt.setString(6, note.getTone().toString() + '\n' + note.getOctave() + '\n' + note.isSharped());
|
||||||
} else {
|
} else if (state instanceof Jukebox) {
|
||||||
dataStmt.setNull(8, Types.VARCHAR);
|
dataStmt.setString(6, ((Jukebox) block.getState()).getPlaying().toString());
|
||||||
}
|
} else if (state instanceof Skull) {
|
||||||
if (block.getState() instanceof Jukebox) {
|
dataStmt.setString(6, String.format("%s\n%s\n%s",
|
||||||
dataStmt.setString(9, ((Jukebox) block.getState()).getPlaying().toString());
|
|
||||||
} else {
|
|
||||||
dataStmt.setNull(9, Types.VARCHAR);
|
|
||||||
}
|
|
||||||
if (block.getState() instanceof Skull) {
|
|
||||||
dataStmt.setString(10, String.format("%s\n%s\n%s",
|
|
||||||
((Skull) block.getState()).getOwner(),
|
((Skull) block.getState()).getOwner(),
|
||||||
((Skull) block.getState()).getSkullType().toString(),
|
((Skull) block.getState()).getSkullType().toString(),
|
||||||
((Skull) block.getState()).getRotation().toString()));
|
((Skull) block.getState()).getRotation().toString()));
|
||||||
} else {
|
} else if (state instanceof CommandBlock) {
|
||||||
dataStmt.setNull(10, Types.VARCHAR);
|
dataStmt.setString(6, ((CommandBlock) block.getState()).getName()
|
||||||
}
|
|
||||||
if (block.getState() instanceof CommandBlock) {
|
|
||||||
dataStmt.setString(11, ((CommandBlock) block.getState()).getName()
|
|
||||||
+ "\n" + ((CommandBlock) block.getState()).getCommand());
|
+ "\n" + ((CommandBlock) block.getState()).getCommand());
|
||||||
} else {
|
} else if (state instanceof CreatureSpawner) {
|
||||||
dataStmt.setNull(11, Types.VARCHAR);
|
dataStmt.setString(6, ((CreatureSpawner) block.getState()).getSpawnedType().toString());
|
||||||
}
|
|
||||||
if (block.getState() instanceof CreatureSpawner) {
|
|
||||||
dataStmt.setString(12, ((CreatureSpawner) block.getState()).getSpawnedType().toString());
|
|
||||||
} else {
|
|
||||||
dataStmt.setNull(12, Types.VARCHAR);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dataStmt.addBatch();
|
dataStmt.addBatch();
|
||||||
|
|
||||||
if (++changed % batchSize == 0) {
|
if (++changed % batchSize == 0) {
|
||||||
dataStmt.executeBatch();
|
dataStmt.executeBatch();
|
||||||
|
if ((System.currentTimeMillis() - startTime) >= 5000L) {
|
||||||
|
String seconds = new DecimalFormat("#0.00").format((double) (System.currentTimeMillis() - startTime) / 1000.0D);
|
||||||
|
War.war.getLogger().log(Level.FINE, "Still saving warzone {0} , {1} seconds elapsed.", new Object[] {zoneName, seconds});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -259,15 +396,49 @@ public class ZoneVolumeMapper {
|
|||||||
databaseConnection.commit();
|
databaseConnection.commit();
|
||||||
dataStmt.close();
|
dataStmt.close();
|
||||||
databaseConnection.close();
|
databaseConnection.close();
|
||||||
|
String seconds = new DecimalFormat("#0.00").format((double) (System.currentTimeMillis() - startTime) / 1000.0D);
|
||||||
|
War.war.getLogger().log(Level.INFO, "Saved warzone {0} in {1} seconds.", new Object[] {zoneName, seconds});
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Location rebase(final Location base, final Location exact) {
|
public static Location rebase(final Location base, final Location exact) {
|
||||||
Validate.isTrue(base.getWorld().equals(exact.getWorld()),
|
|
||||||
"Locations must be in the same world");
|
|
||||||
return new Location(base.getWorld(),
|
return new Location(base.getWorld(),
|
||||||
exact.getBlockX() - base.getBlockX(),
|
exact.getBlockX() - base.getBlockX(),
|
||||||
exact.getBlockY() - base.getBlockY(),
|
exact.getBlockY() - base.getBlockY(),
|
||||||
exact.getBlockZ() - base.getBlockZ());
|
exact.getBlockZ() - base.getBlockZ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void updateFromVersionOneToTwo(String zoneName, Connection connection) throws SQLException {
|
||||||
|
War.war.log("Migrating warzone " + zoneName + " from v1 to v2 of schema...", Level.INFO);
|
||||||
|
|
||||||
|
// We want to do this in a transaction
|
||||||
|
connection.setAutoCommit(false);
|
||||||
|
|
||||||
|
Statement stmt = connection.createStatement();
|
||||||
|
|
||||||
|
// We want to combine all extra columns into a single metadata BLOB one. To delete some columns we need to drop the table so we use a temp one.
|
||||||
|
stmt.executeUpdate("CREATE TEMPORARY TABLE blocks_backup(x BIGINT, y BIGINT, z BIGINT, type TEXT, data SMALLINT, sign TEXT, container BLOB, note INT, record TEXT, skull TEXT, command TEXT, mobid TEXT)");
|
||||||
|
stmt.executeUpdate("INSERT INTO blocks_backup SELECT x, y, z, type, data, sign, container, note, record, skull, command, mobid FROM blocks");
|
||||||
|
stmt.executeUpdate("DROP TABLE blocks");
|
||||||
|
stmt.executeUpdate("CREATE TABLE blocks(x BIGINT, y BIGINT, z BIGINT, type TEXT, data SMALLINT, metadata BLOB)");
|
||||||
|
stmt.executeUpdate("INSERT INTO blocks SELECT x, y, z, type, data, coalesce(container, sign, note, record, skull, command, mobid) FROM blocks_backup");
|
||||||
|
stmt.executeUpdate("DROP TABLE blocks_backup");
|
||||||
|
stmt.executeUpdate("PRAGMA user_version = 2");
|
||||||
|
stmt.close();
|
||||||
|
|
||||||
|
// Commit transaction
|
||||||
|
connection.commit();
|
||||||
|
|
||||||
|
connection.setAutoCommit(true);
|
||||||
|
|
||||||
|
War.war.log("Warzone " + zoneName + " converted! Compacting database...", Level.INFO);
|
||||||
|
|
||||||
|
// Pack the database otherwise we won't get any space savings.
|
||||||
|
// This rebuilds the database completely and takes some time.
|
||||||
|
stmt = connection.createStatement();
|
||||||
|
stmt.execute("VACUUM");
|
||||||
|
stmt.close();
|
||||||
|
|
||||||
|
War.war.log("Migration of warzone " + zoneName + " to v2 of schema finished.", Level.INFO);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ public class WarLogFormatter extends Formatter {
|
|||||||
b.append(" [");
|
b.append(" [");
|
||||||
b.append(arg0.getLevel());
|
b.append(arg0.getLevel());
|
||||||
b.append("] ");
|
b.append("] ");
|
||||||
b.append(arg0.getMessage());
|
b.append(formatMessage(arg0));
|
||||||
b.append(System.getProperty("line.separator"));
|
b.append(System.getProperty("line.separator"));
|
||||||
return b.toString();
|
return b.toString();
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.tommytony.war.volume;
|
package com.tommytony.war.volume;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
@ -50,35 +51,47 @@ public class ZoneVolume extends Volume {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void loadCorners() throws SQLException {
|
public void loadCorners() throws SQLException {
|
||||||
ZoneVolumeMapper.load(this, this.zone.getName(), this.getWorld(), true, 0, 0);
|
Connection conn = ZoneVolumeMapper.getZoneConnection(this, this.zone.getName(), this.getWorld());
|
||||||
|
ZoneVolumeMapper.load(conn, this, this.getWorld(), true, 0, 0, null);
|
||||||
this.isSaved = true;
|
this.isSaved = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resetBlocks() {
|
public void resetBlocks() {
|
||||||
// Load blocks directly from disk and onto the map (i.e. no more in-memory warzone blocks)
|
// Load blocks directly from disk and onto the map (i.e. no more in-memory warzone blocks)
|
||||||
int reset = 0;
|
|
||||||
try {
|
try {
|
||||||
reset = ZoneVolumeMapper.load(this, this.zone.getName(), this.getWorld(), false, 0, Integer.MAX_VALUE);
|
Connection conn = ZoneVolumeMapper.getZoneConnection(this, this.zone.getName(), this.getWorld());
|
||||||
|
ZoneVolumeMapper.load(conn, this, this.getWorld(), false, 0, Integer.MAX_VALUE, null);
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
War.war.log("Failed to load warzone " + zone.getName() + ": " + ex.getMessage(), Level.WARNING);
|
War.war.log("Failed to load warzone " + zone.getName() + ": " + ex.getMessage(), Level.WARNING);
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
War.war.log("Reset " + reset + " blocks in warzone " + this.zone.getName() + ".", java.util.logging.Level.INFO);
|
War.war.log("Reset warzone " + this.zone.getName() + ".", java.util.logging.Level.INFO);
|
||||||
this.isSaved = true;
|
this.isSaved = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset a section of blocks in the warzone.
|
* Reset a section of blocks in the warzone.
|
||||||
*
|
*
|
||||||
|
* @param conn Open connection to warzone database file.
|
||||||
* @param start
|
* @param start
|
||||||
* Starting position for reset.
|
* Starting position for reset.
|
||||||
* @param total
|
* @param total
|
||||||
* Amount of blocks to reset.
|
* Amount of blocks to reset.
|
||||||
|
* @return Changed block count.
|
||||||
* @throws SQLException
|
* @throws SQLException
|
||||||
*/
|
*/
|
||||||
public void resetSection(int start, int total) throws SQLException {
|
public int resetSection(Connection conn, int start, int total, boolean[][][] changes) throws SQLException {
|
||||||
ZoneVolumeMapper.load(this, this.zone.getName(), this.getWorld(), false, start, total);
|
return ZoneVolumeMapper.load(conn, this, this.getWorld(), false, start, total, changes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get total saved blocks for this warzone. This should only be called on nimitz-format warzones.
|
||||||
|
* @return Total saved blocks
|
||||||
|
* @throws SQLException
|
||||||
|
*/
|
||||||
|
public int getTotalSavedBlocks() throws SQLException {
|
||||||
|
return ZoneVolumeMapper.getTotalSavedBlocks(this, this.zone.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -87,9 +100,12 @@ public class ZoneVolume extends Volume {
|
|||||||
* The job will automatically spawn new instances of itself to run every tick until it is done resetting all blocks.
|
* The job will automatically spawn new instances of itself to run every tick until it is done resetting all blocks.
|
||||||
*/
|
*/
|
||||||
public void resetBlocksAsJob() {
|
public void resetBlocksAsJob() {
|
||||||
PartialZoneResetJob job = new PartialZoneResetJob(zone, War.war
|
try {
|
||||||
.getWarConfig().getInt(WarConfig.RESETSPEED));
|
PartialZoneResetJob job = new PartialZoneResetJob(zone, War.war.getWarConfig().getInt(WarConfig.RESETSPEED));
|
||||||
War.war.getServer().getScheduler().runTask(War.war, job);
|
War.war.getServer().getScheduler().runTask(War.war, job);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
War.war.getLogger().log(Level.WARNING, "Failed to reset warzone - cannot get count of saved blocks", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNorthwest(Location block) throws NotNorthwestException, TooSmallException, TooBigException {
|
public void setNorthwest(Location block) throws NotNorthwestException, TooSmallException, TooBigException {
|
||||||
@ -239,10 +255,7 @@ public class ZoneVolume extends Volume {
|
|||||||
|
|
||||||
private static final int MIN_SIZE = 10;
|
private static final int MIN_SIZE = 10;
|
||||||
public boolean tooSmall() {
|
public boolean tooSmall() {
|
||||||
if (!this.hasTwoCorners()) {
|
return this.hasTwoCorners() && (this.getSizeX() < MIN_SIZE || this.getSizeY() < MIN_SIZE || this.getSizeZ() < MIN_SIZE);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return this.getSizeX() < MIN_SIZE || this.getSizeY() < MIN_SIZE || this.getSizeZ() < MIN_SIZE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int MAX_SIZE_DEFAULT = 750;
|
private static final int MAX_SIZE_DEFAULT = 750;
|
||||||
|
Loading…
Reference in New Issue
Block a user