diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/TownyUniverse.java b/Towny/src/main/java/com/palmergames/bukkit/towny/TownyUniverse.java index 541ebfdfd8c..201c361764e 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/TownyUniverse.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/TownyUniverse.java @@ -393,40 +393,98 @@ public Resident getResident(@NotNull UUID residentUUID) { public Optional getResidentOpt(@NotNull UUID residentUUID) { return Optional.ofNullable(getResident(residentUUID)); } - - // Internal Use Only - public void registerResidentUUID(@NotNull Resident resident) throws AlreadyRegisteredException { - Preconditions.checkNotNull(resident, "Resident cannot be null!"); - - if (resident.getUUID() != null) { - if (residentUUIDMap.putIfAbsent(resident.getUUID(), resident) != null) { - throw new AlreadyRegisteredException( - String.format("UUID '%s' was already registered for resident '%s'!", resident.getUUID().toString(), resident.getName()) - ); - } - } + + /** + * Creates and registers a Resident any time except the loading process. Their + * UUID and Name will be stored in the TownyUniverse Maps for residents. + * + * @param residentUUID UUID of the Resident. + * @param residentName Name of the Resident. + * @throws AlreadyRegisteredException Thrown by + * {@link #registerResident(Resident)} when + * the resident's name is already in use by + * another resident. + * @throws InvalidNameException Thrown by if the player does not have a + * name allowed by + * {@link NameValidation#checkAndFilterPlayerName(String)}. + */ + public void newResident(@NotNull UUID residentUUID, String residentName) throws AlreadyRegisteredException, InvalidNameException { + Preconditions.checkNotNull(residentUUID, "UUID cannot be null!"); + Preconditions.checkNotNull(residentName, "Name cannot be null!"); + Resident resident = new Resident(NameValidation.checkAndFilterPlayerName(residentName), residentUUID); + registerResident(resident); } /** - * Register a resident into the internal structures. - * This will allow the resident to be fetched by name and UUID, as well as autocomplete the resident name. + * Creates and registers a Resident during the loading process. Only their UUID + * is added to the TownyUniverse Maps, their name will be stored later when the + * resident's data is loaded in full. * - * If a resident's name or UUID change, the resident must be re-registered into the maps. + * @param residentName String name of the Resident. + * @param residentUUID UUID to put onto the Resident. + */ + @ApiStatus.Internal + public void newResidentInternal(@NotNull String residentName, @NotNull UUID residentUUID) { + Resident resident = new Resident(residentName, residentUUID); + registerResidentUUID(resident); + } + + /** + * Register a resident's name and UUID into the TownyUniverse Maps. This will + * allow the resident to be fetched by name as well as autocomplete the resident + * name in the commands. * - * This does not modify the resident internally, nor saves the resident in the database. + * If a resident's name or UUID change, the resident must be re-registered into + * the maps. + * + * This does not modify the resident internally, nor saves the resident in the + * database. * * @param resident Resident to register. - * @throws AlreadyRegisteredException if another resident has been registered with the same name or UUID. + * @throws AlreadyRegisteredException thrown by + * {@link #registerResidentName(Resident)} if + * another resident has been registered with + * the same name. */ + @ApiStatus.Internal public void registerResident(@NotNull Resident resident) throws AlreadyRegisteredException { Preconditions.checkNotNull(resident, "Resident cannot be null!"); + registerResidentName(resident); + registerResidentUUID(resident); + } + + /** + * Register a resident's UUID into the TownyUniverse Maps. + * This will allow the resident to be fetched by UUID. + * + * Used in Towny's loading process. + * + * @param resident Resident to register a UUID for. + */ + @ApiStatus.Internal + public void registerResidentUUID(@NotNull Resident resident) { + Preconditions.checkNotNull(resident, "Resident cannot be null!"); + Preconditions.checkNotNull(resident.getUUID(), "Resident UUID cannot be null!"); + residentUUIDMap.putIfAbsent(resident.getUUID(), resident); + } + + /** + * Register a resident's name into the TownyUniverse Maps. + * This will allow the resident to be fetched by name as well as autocomplete the resident name in the commands. + * + * @param resident Resident to register a name for. + * @throws AlreadyRegisteredException if another resident has been registered with the same name. + */ + @ApiStatus.Internal + public void registerResidentName(@NotNull Resident resident) throws AlreadyRegisteredException { + Preconditions.checkNotNull(resident, "Resident cannot be null!"); + if (residentNameMap.putIfAbsent(resident.getName().toLowerCase(Locale.ROOT), resident) != null) { throw new AlreadyRegisteredException(String.format("The resident with name '%s' is already registered!", resident.getName())); } residentsTrie.addKey(resident.getName()); - registerResidentUUID(resident); } /** @@ -445,18 +503,35 @@ public void unregisterResident(@NotNull Resident resident) throws NotRegisteredE residentsTrie.removeKey(resident.getName()); - if (resident.getUUID() != null) { - if (residentUUIDMap.remove(resident.getUUID()) == null) { - throw new NotRegisteredException(String.format("The resident with the UUID '%s' is not registered!", resident.getUUID().toString())); - } + if (resident.getUUID() != null && residentUUIDMap.remove(resident.getUUID()) == null) { + throw new NotRegisteredException(String.format("The resident with the UUID '%s' is not registered!", resident.getUUID().toString())); } } - @Unmodifiable + /** + * Unregister a resident from the internal structures. + * This does not modify the resident internally, nor performs any database operations using the resident. + * + * @param uuid UUID of resident to unregister + */ + public void unregisterResident(@NotNull UUID uuid) { + Preconditions.checkNotNull(uuid, "UUID cannot be null!"); + Resident resident = residentUUIDMap.get(uuid); + Preconditions.checkNotNull(resident, "Resident cannot be null!"); + residentNameMap.remove(resident.getName().toLowerCase()); + residentsTrie.removeKey(resident.getName()); + residentUUIDMap.remove(resident.getUUID()); + } + + @Unmodifiable public Collection getResidents() { return Collections.unmodifiableCollection(residentNameMap.values()); } + public Set getResidentUUIDs() { + return residentUUIDMap.keySet(); + } + /** * @return number of residents that Towny has. */ @@ -525,48 +600,47 @@ public Collection getTowns() { return Collections.unmodifiableCollection(townNameMap.values()); } + public Set getTownUUIDs() { + return townUUIDMap.keySet(); + } + public Trie getTownsTrie() { return townsTrie; } + /** + * Used in Towny's Loading process to create a Town, and add it's UUID to the + * UUID map for Towns. The Town's name will be added to the Name-related Maps + * later on in the loading process. + * + * @param name Name of the Town. + * @param uuid UUID to assign to the Town. + */ @ApiStatus.Internal - public void newTownInternal(String name, UUID uuid) throws AlreadyRegisteredException, com.palmergames.bukkit.towny.exceptions.InvalidNameException { - newTown(name, uuid); + public void newTownInternal(String name, UUID uuid) { + Town town = new Town(name, uuid); + registerTownUUID(town); } /** - * Create a new town from the string name. + * Create a new town from the String name, assigns a random UUID. The Town is + * then registered in the TownyUniverse Maps. * - * @param name Town name + * @param name Name to assign to the Town. * @throws AlreadyRegisteredException Town name is already in use. - * @throws InvalidNameException Town name is invalid. + * @throws InvalidNameException Town name is invalid according to {@link NameValidation#checkAndFilterTownNameOrThrow(String)}. */ public void newTown(@NotNull String name) throws AlreadyRegisteredException, InvalidNameException { - Preconditions.checkNotNull(name, "Name cannot be null!"); - - newTown(name, UUID.randomUUID()); - } - - private void newTown(String name, UUID uuid) throws AlreadyRegisteredException, InvalidNameException { - Preconditions.checkArgument(uuid != null, "uuid may not be null"); - String filteredName = NameValidation.checkAndFilterTownNameOrThrow(name); - - Town town = new Town(filteredName, uuid); + Preconditions.checkNotNull(name, "Town name cannot be null!"); + Town town = new Town(NameValidation.checkAndFilterTownNameOrThrow(name), UUID.randomUUID()); registerTown(town); } - - // This is used internally since UUIDs are assigned after town objects are created. - public void registerTownUUID(@NotNull Town town) throws AlreadyRegisteredException { + + @ApiStatus.Internal + public void registerTownUUID(@NotNull Town town) { Preconditions.checkNotNull(town, "Town cannot be null!"); - - if (town.getUUID() != null) { - - if (townUUIDMap.containsKey(town.getUUID())) { - throw new AlreadyRegisteredException("UUID of town " + town.getName() + " was already registered!"); - } - - townUUIDMap.put(town.getUUID(), town); - } + Preconditions.checkNotNull(town.getUUID(), "Town UUID cannot be null!"); + townUUIDMap.putIfAbsent(town.getUUID(), town); } /** @@ -579,11 +653,11 @@ public void registerTownUUID(@NotNull Town town) throws AlreadyRegisteredExcepti */ public void registerTown(@NotNull Town town) throws AlreadyRegisteredException { Preconditions.checkNotNull(town, "Town cannot be null!"); - + if (townNameMap.putIfAbsent(town.getName().toLowerCase(Locale.ROOT), town) != null) { throw new AlreadyRegisteredException(String.format("The town with name '%s' is already registered!", town.getName())); } - + townsTrie.addKey(town.getName()); registerTownUUID(town); } @@ -598,20 +672,34 @@ public void registerTown(@NotNull Town town) throws AlreadyRegisteredException { */ public void unregisterTown(@NotNull Town town) throws NotRegisteredException { Preconditions.checkNotNull(town, "Town cannot be null!"); - + if (townNameMap.remove(town.getName().toLowerCase(Locale.ROOT)) == null) { throw new NotRegisteredException(String.format("The town with the name '%s' is not registered!", town.getName())); } - + townsTrie.removeKey(town.getName()); - - if (town.getUUID() != null) { - if (townUUIDMap.remove(town.getUUID()) == null) { - throw new NotRegisteredException(String.format("The town with the UUID '%s' is not registered!", town.getUUID().toString())); - } + + if (town.getUUID() != null && townUUIDMap.remove(town.getUUID()) == null) { + throw new NotRegisteredException(String.format("The town with the UUID '%s' is not registered!", town.getUUID().toString())); } } + /** + * Used to unregister a town from the TownyUniverse internal maps. + * + * This does not delete a town, nor perform any actions that affect the town internally. + * + * @param uuid UUID of Town to unregister + */ + public void unregisterTown(@NotNull UUID uuid) { + Preconditions.checkNotNull(uuid, "UUID cannot be null!"); + Town town = townUUIDMap.get(uuid); + Preconditions.checkNotNull(town, "Town cannot be null!"); + townNameMap.remove(town.getName().toLowerCase()); + townsTrie.removeKey(town.getName()); + townUUIDMap.remove(town.getUUID()); + } + // =========== Nation Methods =========== /** @@ -690,23 +778,48 @@ public Nation getNation(@NotNull UUID nationUUID) { public Collection getNations() { return Collections.unmodifiableCollection(nationNameMap.values()); } - + + public Set getNationUUIDs() { + return nationUUIDMap.keySet(); + } + public int getNumNations() { return nationNameMap.size(); } - // This is used internally since UUIDs are assigned after nation objects are created. - public void registerNationUUID(@NotNull Nation nation) throws AlreadyRegisteredException { - Preconditions.checkNotNull(nation, "Nation cannot be null!"); - - if (nation.getUUID() != null) { + /** + * Registers a Nation with only a UUID present as data. Meant only to be used by + * Towny in the loading process. + * + * @param nationName String name of the nation + * @param nationUUID UUID to put onto the Nation. + */ + @ApiStatus.Internal + public void newNationInternal(@NotNull String nationName, @NotNull UUID nationUUID) { + Nation nation = new Nation(nationName, nationUUID); + registerNationUUID(nation); + } - if (nationUUIDMap.containsKey(nation.getUUID())) { - throw new AlreadyRegisteredException("UUID of nation " + nation.getName() + " was already registered!"); - } + /** + * Create a new Nation from the String name, assigns a random UUID. The Nation + * is then registered in the TownyUniverse Maps. + * + * @param name Name to assign to the Nation. + * @throws AlreadyRegisteredException Nation name is already in use. + * @throws InvalidNameException Nation name is invalid according to + * {@link NameValidation#checkAndFilterNationameOrThrow(String)}. + */ + public void newNation(@NotNull String name) throws InvalidNameException, AlreadyRegisteredException { + Preconditions.checkNotNull(name, "Name cannot be null!"); + Nation nation = new Nation(NameValidation.checkAndFilterNationNameOrThrow(name), UUID.randomUUID()); + registerNation(nation); + } - nationUUIDMap.put(nation.getUUID(), nation); - } + @ApiStatus.Internal + public void registerNationUUID(@NotNull Nation nation) { + Preconditions.checkNotNull(nation, "Nation cannot be null!"); + Preconditions.checkNotNull(nation.getUUID(), "Nation UUID cannot be null!"); + nationUUIDMap.putIfAbsent(nation.getUUID(), nation); } /** @@ -745,19 +858,45 @@ public void unregisterNation(@NotNull Nation nation) throws NotRegisteredExcepti nationsTrie.removeKey(nation.getName()); - if (nation.getUUID() != null) { - if (nationUUIDMap.remove(nation.getUUID()) == null) { - throw new NotRegisteredException(String.format("The nation with the UUID '%s' is not registered!", nation.getUUID().toString())); - } + if (nation.getUUID() != null && nationUUIDMap.remove(nation.getUUID()) == null) { + throw new NotRegisteredException(String.format("The nation with the UUID '%s' is not registered!", nation.getUUID().toString())); } } + /** + * Used to unregister a nation from the TownyUniverse internal maps. + * + * This does not delete a nation, nor perform any actions that affect the nation internally. + * + * @param uuid UUID of Nation to unregister + */ + public void unregisterNation(@NotNull UUID uuid) { + Preconditions.checkNotNull(uuid, "UUID cannot be null!"); + Nation nation = nationUUIDMap.get(uuid); + Preconditions.checkNotNull(nation, "Nation cannot be null!"); + nationNameMap.remove(nation.getName().toLowerCase()); + nationsTrie.removeKey(nation.getName()); + nationUUIDMap.remove(nation.getUUID()); + } + public Trie getNationsTrie() { return nationsTrie; } // =========== World Methods =========== + /** + * Registers a TownyWorld with only a UUID present as data. + * Meant only to be used by Towny in the loading process. + * @param worldName String name to put onto the TownyWorld. + * @param worldUUID UUID to put onto the TownyWorld. + */ + @ApiStatus.Internal + public void newWorldInternal(@NotNull String worldName, @NotNull UUID worldUUID) { + TownyWorld world = new TownyWorld(worldName, worldUUID); + registerTownyWorldUUID(world); + } + /** * Causes a new TownyWorld object to be made in the Universe, from a Bukkit World. */ @@ -770,6 +909,12 @@ public void newWorld(@NotNull World world) { townyWorld.save(); } + public void registerTownyWorldUUID(TownyWorld world) { + Preconditions.checkNotNull(world, "TownyWorld cannot be null!"); + Preconditions.checkNotNull(world.getUUID(), "TownyWorld UUID cannot be null!"); + worldUUIDMap.putIfAbsent(world.getUUID(), world); + } + public void registerTownyWorld(@NotNull TownyWorld world) { Preconditions.checkNotNull(world, "World cannot be null!"); worldUUIDMap.putIfAbsent(world.getUUID(), world); @@ -1111,8 +1256,12 @@ public void removeSpawnPoint(SpawnPointLocation point) { public List getJails() { return new ArrayList<>(getJailUUIDMap().values()); } - - public Map getJailUUIDMap() { + + public Set getJailUUIDs() { + return jailUUIDMap.keySet(); + } + + public Map getJailUUIDMap() { return jailUUIDMap; } @@ -1135,15 +1284,19 @@ public void registerJail(Jail jail) { public void unregisterJail(Jail jail) { jailUUIDMap.remove(jail.getUUID()); } - + + public void unregisterJail(UUID uuid) { + jailUUIDMap.remove(uuid); + } + /** * Used in loading only. * * @param uuid UUID of the given jail, taken from the Jail filename. */ - public void newJailInternal(String uuid) { + public void newJailInternal(UUID uuid) { // Remaining fields are set later on in the loading process. - Jail jail = new Jail(UUID.fromString(uuid), null, null, new ArrayList()); + Jail jail = new Jail(uuid, null, null, new ArrayList()); registerJail(jail); } diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/command/NationCommand.java b/Towny/src/main/java/com/palmergames/bukkit/towny/command/NationCommand.java index de4212dbbf1..6d7bbbee4ba 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/command/NationCommand.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/command/NationCommand.java @@ -963,9 +963,8 @@ public static void newNation(CommandSender sender, String name, Town capitalTown public static Nation newNation(String name, Town town) throws TownyException { TownyUniverse townyUniverse = TownyUniverse.getInstance(); - UUID nationUUID = UUID.randomUUID(); - townyUniverse.getDataSource().newNation(name, nationUUID); - Nation nation = townyUniverse.getNation(nationUUID); + townyUniverse.newNation(name); + Nation nation = townyUniverse.getNation(name); // Should never happen. if (nation == null) { diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/db/FlatFileSaveTask.java b/Towny/src/main/java/com/palmergames/bukkit/towny/db/FlatFileSaveTask.java index 5170948fc6b..6bf90e33bad 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/db/FlatFileSaveTask.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/db/FlatFileSaveTask.java @@ -3,29 +3,32 @@ import com.palmergames.bukkit.towny.TownyMessaging; import com.palmergames.util.FileMgmt; -import java.util.List; +import java.nio.file.Paths; +import java.util.Map; +import java.io.IOException; public class FlatFileSaveTask implements Runnable { - private final List list; + private final Map map; private final String path; /** - * Constructor to save a list - * @param list - list to save. - * @param path - path on filesystem. + * Constructor to save a Map to a file. + * @param map Map to save. + * @param path String path on filesystem. */ - public FlatFileSaveTask(List list, String path) { - this.list = list; + public FlatFileSaveTask(Map map, String path) { + this.map = map; this.path = path; } @Override public void run() { try { - FileMgmt.listToFile(list, path); - } catch (NullPointerException ex) { + FileMgmt.mapToFile(map, Paths.get(path)); + } catch (IOException ex) { TownyMessaging.sendErrorMsg("Null Error saving to file - " + path); + ex.printStackTrace(); } } } \ No newline at end of file diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/db/SQLSchema.java b/Towny/src/main/java/com/palmergames/bukkit/towny/db/SQLSchema.java index b4bc58c95ba..f451ca89643 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/db/SQLSchema.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/db/SQLSchema.java @@ -377,11 +377,11 @@ private static List getTownBlockColumns() { columns.add(new ColumnData("taxed", "bool NOT NULL DEFAULT '1'")); columns.add(new ColumnData("town", "mediumtext")); columns.add(new ColumnData("resident", "mediumtext")); - columns.add(new ColumnData("type", "TINYINT NOT NULL DEFAULT '0'")); + columns.add(new ColumnData("type", "TINYINT NOT NULL DEFAULT '0'")); // TODO: Check if this is still used. columns.add(new ColumnData("typeName", "mediumtext")); columns.add(new ColumnData("outpost", "bool NOT NULL DEFAULT '0'")); columns.add(new ColumnData("permissions", "mediumtext NOT NULL")); - columns.add(new ColumnData("locked", "bool NOT NULL DEFAULT '0'")); + columns.add(new ColumnData("locked", "bool NOT NULL DEFAULT '0'")); // TODO: Check if this is still used. columns.add(new ColumnData("changed", "bool NOT NULL DEFAULT '0'")); columns.add(new ColumnData("metadata", "mediumtext DEFAULT NULL")); columns.add(new ColumnData("groupID", "VARCHAR(36) DEFAULT NULL")); diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/db/TownyDataSource.java b/Towny/src/main/java/com/palmergames/bukkit/towny/db/TownyDataSource.java index 96a70930853..0c4d604a821 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/db/TownyDataSource.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/db/TownyDataSource.java @@ -10,6 +10,7 @@ import com.palmergames.bukkit.towny.event.DeleteNationEvent; import com.palmergames.bukkit.towny.exceptions.AlreadyRegisteredException; import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; +import com.palmergames.bukkit.towny.exceptions.ObjectCouldNotBeLoadedException; import com.palmergames.bukkit.towny.exceptions.TownyException; import com.palmergames.bukkit.towny.object.District; import com.palmergames.bukkit.towny.object.Nation; @@ -25,23 +26,53 @@ import org.jetbrains.annotations.Nullable; import java.io.IOException; +import java.util.Collection; +import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; + /* + * The TownyDataSource acts as an abstract plan for operating upon + * the Towny database. Methods are contained primarily in the + * TownyDatabaseHandler class, which relies upon a Source class: + * ie: TownyFlatfileSource or TownySQLSource, which will then + * complete operations that require directly reading/writing from + * the database. + * + * TownyDatabaseHandler is responsible for using the database source + * methods, removing individual objects, renaming objects, operating + * with aspects of the Database which are always stored in Flatfile: + * PlotBlockData, Snapshot and Regen queues. + * + * The database source classes are responsible for providing keys, + * loading and saving objects using Maps, deleting objects. + * + * Creating new database sources is achieved by creating a new class + * which extends TownyDatabaseHandler, and implementing the required + * methods, following the instructions found in those methods' + * javadocs. + * * --- : Loading process : --- * - * Load all the names/keys for each world, nation, town, and resident. - * Load each world, which loads it's town blocks. - * Load nations, towns, and residents. + * - Load all the keys for each world, nation, town, and resident, jail, + * plotgroup, townblock into TownyUniverse. + * - Parse over each key loaded into TownyUniverse, loading each object + * by requesting Maps made up of each object's data from the + * DatabaseSource classes. + * + * --- : Saving process : --- + * + * - Save objects by dumping their data into Maps which are then + * processed by the DatabaseSource classes. */ -/* - * Loading Towns: - * Make sure to load TownBlocks, then HomeBlock, then Spawn. +/** + * @author LlmDl */ public abstract class TownyDataSource { @@ -88,292 +119,538 @@ public boolean saveQueues() { abstract public void finishTasks(); - abstract public boolean loadTownBlockList(); + /* + * Load Lists (Gathering UUIDs to load in full later.) + * Methods are found in TownyFlatfile/SQlSource classes. + */ + /** + * @return true after loading all of the Jails' UUIDs into {@link TownyUniverse#newJailInternal(UUID)} + */ + abstract public boolean loadJailList(); + + /** + * @return true after loading all of the PlotGroups' UUIDs into {@link TownyUniverse#newPlotGroupInternal(UUID)} + */ + abstract public boolean loadPlotGroupList(); + + /** + * @return true after loading all of the Districts' UUIDs into {@link TownyUniverse#newDistrictInternal(UUID)} + */ + abstract public boolean loadDistrictList(); + + /** + * @return true after loading all of the Residents' UUIDs into {@link TownyUniverse#newResidentInternal(UUID)} + */ abstract public boolean loadResidentList(); + /** + * @return true after loading all of the Towns' UUIDs into {@link TownyUniverse#newTownInternal(UUID)} + */ abstract public boolean loadTownList(); + /** + * @return true after loading all of the Nations' UUIDs into {@link TownyUniverse#newNationInternal(UUID)} + */ abstract public boolean loadNationList(); + /** + * @return true after loading all of the Worlds' UUIDs into {@link TownyUniverse#newWorldInternal(UUID)} + */ abstract public boolean loadWorldList(); + /** + * @return true after loading all of the TownBlocks into {@link TownyUniverse#addTownBlock(TownBlock)} + */ + abstract public boolean loadTownBlockList(); + abstract public boolean loadRegenList(); - abstract public boolean loadTownBlocks(); + /* + * Load all objects of the given type, using the UUIDs gathered into TownyUniverse. + * Methods are found in TownyDatabaseHandler. + */ - abstract public boolean loadJailList(); + abstract public boolean loadJails(); + + abstract public boolean loadPlotGroups(); - abstract public boolean loadResident(Resident resident); + abstract public boolean loadDistricts(); - abstract public boolean loadTown(Town town); + abstract public boolean loadResidents(); - abstract public boolean loadNation(Nation nation); + abstract public boolean loadTowns(); - abstract public boolean loadWorld(TownyWorld world); - - abstract public boolean loadJail(Jail jail); + abstract public boolean loadNations(); - abstract public boolean loadPlotGroupList(); + abstract public boolean loadWorlds(); - abstract public boolean loadPlotGroup(PlotGroup group); + abstract public boolean loadTownBlocks(); - abstract public boolean loadDistrictList(); + abstract public boolean loadCooldowns(); - abstract public boolean loadDistrict(District district); + /* + * Load all objects of the given type, using the UUIDs gathered into TownyUniverse. + * Methods are found in TownyFlatfile/SQlSource classes. + */ - abstract public boolean saveRegenList(); + /** + * @param uuids Set of UUIDs to use. + * @return true after calling {@link #loadJailData(UUID)} on each of the given + * UUIDs. + * @throws ObjectCouldNotBeLoadedException if {@link #loadJailData(UUID)} is + * unsuccessful. Your error message + * should specify which file failed to + * load and where it is in the database. + */ + abstract public boolean loadJailUUIDs(Set uuids) throws ObjectCouldNotBeLoadedException; - abstract public boolean saveResident(Resident resident); + /** + * @param uuids Set of UUIDs to use. + * @return true after calling {@link #loadPlotGroupData(UUID)} on each of the + * given UUIDs. + * @throws ObjectCouldNotBeLoadedException if {@link #loadPlotGroupData(UUID)} + * is unsuccessful. Your error message + * should specify which file failed to + * load and where it is in the database. + */ + abstract public boolean loadPlotGroupUUIDs(Set uuids) throws ObjectCouldNotBeLoadedException; - abstract public boolean saveHibernatedResident(UUID uuid, long registered); - - abstract public boolean saveTown(Town town); - - abstract public boolean savePlotGroup(PlotGroup group); - - abstract public boolean saveDistrict(District district); - - abstract public boolean saveJail(Jail jail); + /** + * @param uuids Set of UUIDs to use. + * @return true after calling {@link #loadDistrictData(UUID)} on each of the + * given UUIDs. + * @throws ObjectCouldNotBeLoadedException if {@link #loadDistrictData(UUID)} is + * unsuccessful. Your error message + * should specify which file failed to + * load and where it is in the database. + */ + abstract public boolean loadDistrictUUIDs(Set uuids) throws ObjectCouldNotBeLoadedException; - abstract public boolean saveNation(Nation nation); + /** + * @param uuids Set of UUIDs to use. + * @return true after calling {@link #loadResidentData(UUID)} on each of the + * given UUIDs. + * @throws ObjectCouldNotBeLoadedException if {@link #loadResidentData(UUID)} is + * unsuccessful. Your error message + * should specify which file failed to + * load and where it is in the database. + */ + abstract public boolean loadResidentUUIDs(Set uuids) throws ObjectCouldNotBeLoadedException; - abstract public boolean saveWorld(TownyWorld world); + /** + * @param uuids Set of UUIDs to use. + * @return true after calling {@link #loadTownData(UUID)} on each of the given + * UUIDs. + * @throws ObjectCouldNotBeLoadedException if {@link #loadTownData(UUID)} is + * unsuccessful. Your error message + * should specify which file failed to + * load and where it is in the database. + */ + abstract public boolean loadTownUUIDs(Set uuids) throws ObjectCouldNotBeLoadedException; - abstract public boolean saveTownBlock(TownBlock townBlock); + /** + * @param uuids Set of UUIDs to use. + * @return true after calling {@link #loadNationData(UUID)} on each of the given + * UUIDs. + * @throws ObjectCouldNotBeLoadedException if {@link #loadNationData(UUID)} is + * unsuccessful. Your error message + * should specify which file failed to + * load and where it is in the database. + */ + abstract public boolean loadNationUUIDs(Set uuids) throws ObjectCouldNotBeLoadedException; - abstract public boolean savePlotData(PlotBlockData plotChunk); + /** + * @param uuids Set of UUIDs to use. + * @return true after calling {@link #loadWorldData(UUID)} on each of the given + * UUIDs. + * @throws ObjectCouldNotBeLoadedException if {@link #loadWorldData(UUID)} is + * unsuccessful. Your error message + * should specify which file failed to + * load and where it is in the database. + */ + abstract public boolean loadWorldUUIDs(Set uuids) throws ObjectCouldNotBeLoadedException; - abstract public PlotBlockData loadPlotData(String worldName, int x, int z); + /** + * @param townBlocks Collection of TownBlocks to use. + * @return true after calling {@link #loadTownBlock(TownBlock)} on each of the + * given TownBlocks. + * @throws ObjectCouldNotBeLoadedException if {@link #loadTownBlock(TownBlock)} + * is unsuccessful. Your error message + * should specify which file failed to + * load and where it is in the database. + */ + abstract public boolean loadTownBlocks(Collection townBlocks) throws ObjectCouldNotBeLoadedException; - abstract public PlotBlockData loadPlotData(TownBlock townBlock); - - abstract public boolean hasPlotData(TownBlock townBlock); + /* + * Load object Data from the database into Memory, to be entered into the Objects themselves. + * Methods are found in the TownyDatabaseHandler class. + */ - abstract public void deletePlotData(PlotBlockData plotChunk); + abstract public boolean loadJailData(UUID uuid); - abstract public void deleteResident(Resident resident); + abstract public boolean loadPlotGroupData(UUID uuid); - abstract public void deleteHibernatedResident(UUID uuid); - - abstract public void deleteTown(Town town); + abstract public boolean loadDistrictData(UUID uuid); - abstract public void deleteNation(Nation nation); + abstract public boolean loadResidentData(UUID uuid); - abstract public void deleteWorld(TownyWorld world); + abstract public boolean loadTownData(UUID uuid); - abstract public void deleteTownBlock(TownBlock townBlock); + abstract public boolean loadNationData(UUID uuid); - abstract public void deleteFile(String file); - - abstract public void deletePlotGroup(PlotGroup group); - - abstract public void deleteDistrict(District district); - - abstract public void deleteJail(Jail jail); - - abstract public CompletableFuture> getHibernatedResidentRegistered(UUID uuid); + abstract public boolean loadWorldData(UUID uuid); - public boolean cleanup() { + abstract public boolean loadTownBlock(TownBlock townBlock); - return true; + /* + * Load object from the database into Memory, to be entered into the Objects + * themselves, not used by Towny itself. + */ + public boolean loadJail(Jail jail) { + return loadJailData(jail.getUUID()); } - public boolean loadResidents() { - - TownyMessaging.sendDebugMsg("Loading Residents"); + public boolean loadPlotGroup(PlotGroup group) { + return loadPlotGroupData(group.getUUID()); + } - for (Resident resident : universe.getResidents()) { - if (!loadResident(resident)) { - plugin.getLogger().severe("Loading Error: Could not read resident data '" + resident.getName() + "'."); - return false; - } - } - return true; + public boolean loadDistrict(District district) { + return loadDistrictData(district.getUUID()); } - public boolean loadTowns() { + public boolean loadResident(Resident resident) { + return loadResidentData(resident.getUUID()); + } - TownyMessaging.sendDebugMsg("Loading Towns"); - for (Town town : universe.getTowns()) - if (!loadTown(town)) { - plugin.getLogger().severe("Loading Error: Could not read town data '" + town.getName() + "'."); - return false; - } - return true; + public boolean loadTown(Town town) { + return loadTownData(town.getUUID()); } - public boolean loadNations() { + public boolean loadNation(Nation nation) { + return loadNationData(nation.getUUID()); + } - TownyMessaging.sendDebugMsg("Loading Nations"); - for (Nation nation : universe.getNations()) - if (!loadNation(nation)) { - plugin.getLogger().severe("Loading Error: Could not read nation data '" + nation.getName() + "'."); - return false; - } - return true; + public boolean loadWorld(TownyWorld world) { + return loadWorldData(world.getUUID()); } - public boolean loadWorlds() { + /* + * Get objects as Maps for loading. Methods found in TownyFlatfile/SQLSource classes. + */ - TownyMessaging.sendDebugMsg("Loading Worlds"); - for (TownyWorld world : universe.getTownyWorlds()) - if (!loadWorld(world)) { - plugin.getLogger().severe("Loading Error: Could not read world data '" + world.getName() + "'."); - return false; - } - return true; - } - - public boolean loadJails() { - TownyMessaging.sendDebugMsg("Loading Jails"); - for (Jail jail : universe.getJails()) { - if (!loadJail(jail)) { - plugin.getLogger().severe("Loading Error: Could not read jail data '" + jail.getUUID() + "'."); - return false; - } - } - return true; - } + /** + * @param uuid UUID to use. + * @return Map<String, String> populated with the keys and their + * values for a jail with the given UUID, which will be used to load the + * jail with data. + */ + abstract public Map getJailMap(UUID uuid); + + /** + * @param uuid UUID to use. + * @return Map<String, String> populated with the keys and their + * values for a plot group with the given UUID, which will be used to + * load the plot group with data. + */ + abstract public Map getPlotGroupMap(UUID uuid); + + /** + * @param uuid UUID to use. + * @return Map<String, String> populated with the keys and their values + * for a district with the given UUID, which will be used to load the + * district with data. + */ + abstract public Map getDistrictMap(UUID uuid); + + /** + * @param uuid UUID to use. + * @return Map<String, String> populated with the keys and their + * values for a resident with the given UUID, which will be used to load + * the resident with data. + */ + abstract public Map getResidentMap(UUID uuid); + + /** + * @param uuid UUID to use. + * @return Map<String, String> populated with the keys and their + * values for a town with the given UUID, which will be used to load the + * town with data. + */ + abstract public Map getTownMap(UUID uuid); + + /** + * @param uuid UUID to use. + * @return Map<String, String> populated with the keys and their + * values for a nation with the given UUID, which will be used to load + * the nation with data. + */ + abstract public Map getNationMap(UUID uuid); + + /** + * @param uuid UUID to use. + * @return Map<String, String> populated with the keys and their + * values for a world with the given UUID, which will be used to load + * the world with data. + */ + abstract public Map getWorldMap(UUID uuid); + + /** + * @param townBlock TownBlock to use. + * @return Map<String, String> populated with the keys and their + * values for the given TownBlock, which will be used to load the + * townblock with data. + */ + abstract public Map getTownBlockMap(TownBlock townBlock); + + /* + * Legacy database entries that still store a list of keys in a file. + * Methods are found in TownyDatabaseHandler. + */ + + abstract public boolean saveRegenList(); + + /* + * Individual objects saving methods. Methods are found in TownyFlatfile/SQlSource classes. + */ + + /** + * @param jail Jail to save. + * @param data Map<String, Object> which contains the keys and values + * representing a Jail's data. + * @return true when the Jail is saved to the database successfully. + */ + abstract public boolean saveJail(Jail jail, Map data); + + /** + * @param group PlotGroup to save. + * @param data Map<String, Object> which contains the keys and values + * representing a PlotGroup's data. + * @return true when the PlotGroup is saved to the database successfully. + */ + abstract public boolean savePlotGroup(PlotGroup group, Map data); + + /** + * @param district District to save. + * @param data Map<String, Object> which contains the keys and values + * representing a District's data. + * @return true when the District is saved to the database successfully. + */ + abstract public boolean saveDistrict(District district, Map data); + + /** + * @param resident Resident to save. + * @param data Map<String, Object> which contains the keys and + * values representing a Resident's data. + * @return true when the Resident is saved to the database successfully. + */ + abstract public boolean saveResident(Resident resident, Map data); + + /** + * @param uuid UUID to save. + * @param data Map<String, Object> which contains the keys and values + * representing a HibernatedResident's data. + * @return true when the HibernatedResident is saved to the database + * successfully. + */ + abstract public boolean saveHibernatedResident(UUID uuid, Map data); + + /** + * @param town Town to save. + * @param data Map<String, Object> which contains the keys and values + * representing a Town's data. + * @return true when the Town is saved to the database successfully. + */ + abstract public boolean saveTown(Town town, Map data); + + /** + * @param nation Nation to save. + * @param data Map<String, Object> which contains the keys and + * values representing a Nation's data. + * @return true when the Nation is saved to the database successfully. + */ + abstract public boolean saveNation(Nation nation, Map data); + + /** + * @param world TownyWorld to save. + * @param data Map<String, Object> which contains the keys and values + * representing a TownyWorld's data. + * @return true when the TownyWorld is saved to the database successfully. + */ + abstract public boolean saveWorld(TownyWorld world, Map data); + + /** + * @param townBlock TownBlock to save. + * @param data Map<String, Object> which contains the keys and + * values representing a TownBlock's data. + * @return true when the TownBlock is saved to the database successfully. + */ + abstract public boolean saveTownBlock(TownBlock townBlock, Map data); + + /* + * Individual objects saving methods. Methods are found in TownyDataBaseHandler. + */ + + abstract public boolean saveJail(Jail jail); + + abstract public boolean savePlotGroup(PlotGroup group); + + abstract public boolean saveDistrict(District district); + + abstract public boolean saveResident(Resident resident); + + abstract public boolean saveHibernatedResident(UUID uuid, long registered); - public boolean loadPlotGroups() { - TownyMessaging.sendDebugMsg("Loading PlotGroups"); - for (PlotGroup group : universe.getGroups()) { - if (!loadPlotGroup(group)) { - plugin.getLogger().severe("Loading Error: Could not read PlotGroup data: '" + group.getUUID() + "'."); - return false; - } - } - return true; - } + abstract public boolean saveTown(Town town); - public boolean loadDistricts() { - TownyMessaging.sendDebugMsg("Loading Districts"); - for (District district : universe.getDistricts()) { - if (!loadDistrict(district)) { - plugin.getLogger().severe("Loading Error: Could not read District data: '" + district.getUUID() + "'."); - return false; - } - } - return true; - } + abstract public boolean saveNation(Nation nation); - abstract public boolean loadCooldowns(); + abstract public boolean saveWorld(TownyWorld world); + + abstract public boolean saveTownBlock(TownBlock townBlock); + + abstract public boolean saveCooldowns(); /* * Save all of category */ - public boolean saveResidents() { - - TownyMessaging.sendDebugMsg("Saving Residents"); - for (Resident resident : universe.getResidents()) - saveResident(resident); + public boolean saveJails() { + TownyMessaging.sendDebugMsg("Saving all Jails"); + universe.getJails().stream().forEach(j -> saveJail(j)); return true; } - + public boolean savePlotGroups() { - TownyMessaging.sendDebugMsg("Saving PlotGroups"); - for (PlotGroup plotGroup : universe.getGroups()) - /* - * Only save plotgroups which actually have townblocks associated with them. - */ - if (plotGroup.hasTownBlocks()) - savePlotGroup(plotGroup); - else - deletePlotGroup(plotGroup); + TownyMessaging.sendDebugMsg("Saving all PlotGroups"); + universe.getGroups().stream().forEach(g -> vetPlotGroupForSaving(g)); return true; } public boolean saveDistricts() { - TownyMessaging.sendDebugMsg("Saving Districts"); - for (District district : universe.getDistricts()) - /* - * Only save districts which actually have townblocks associated with them. - */ - if (district.hasTownBlocks()) - saveDistrict(district); - else - deleteDistrict(district); + TownyMessaging.sendDebugMsg("Saving all Districts"); + universe.getDistricts().stream().forEach(d -> saveDistrict(d)); return true; } - public boolean saveJails() { - TownyMessaging.sendDebugMsg("Saving Jails"); - for (Jail jail : universe.getJails()) - saveJail(jail); + private void vetPlotGroupForSaving(PlotGroup g) { + // Only save plotgroups which actually have townblocks associated with them. + if (g.hasTownBlocks()) + savePlotGroup(g); + else + deletePlotGroup(g); + } + + public boolean saveResidents() { + TownyMessaging.sendDebugMsg("Saving all Residents"); + universe.getResidents().stream().forEach(r -> saveResident(r)); return true; } - - public boolean saveTowns() { - TownyMessaging.sendDebugMsg("Saving Towns"); - for (Town town : universe.getTowns()) - saveTown(town); + public boolean saveTowns() { + TownyMessaging.sendDebugMsg("Saving all Towns"); + universe.getTowns().stream().forEach(t -> saveTown(t)); return true; } public boolean saveNations() { - - TownyMessaging.sendDebugMsg("Saving Nations"); - for (Nation nation : universe.getNations()) - saveNation(nation); + TownyMessaging.sendDebugMsg("Saving all Nations"); + universe.getNations().stream().forEach(n -> saveNation(n)); return true; } public boolean saveWorlds() { - - TownyMessaging.sendDebugMsg("Saving Worlds"); - for (TownyWorld world : universe.getTownyWorlds()) - saveWorld(world); + TownyMessaging.sendDebugMsg("Saving all Worlds"); + universe.getTownyWorlds().stream().forEach(w -> saveWorld(w)); return true; } - + public boolean saveTownBlocks() { - TownyMessaging.sendDebugMsg("Saving Townblocks"); - for (Town town : universe.getTowns()) { - for (TownBlock townBlock : town.getTownBlocks()) - saveTownBlock(townBlock); - } + TownyMessaging.sendDebugMsg("Saving all Townblocks"); + universe.getTowns().stream().forEach(t -> t.saveTownBlocks()); return true; } - - abstract public boolean saveCooldowns(); - // Database functions + /* + * Delete methods found in the TownyFlatfile/SQLSource classes. + */ - abstract public void removeResident(Resident resident); + /** + * @param jail Jail to delete from the Database. + */ + abstract public void deleteJail(Jail jail); - abstract public void removeTownBlock(TownBlock townBlock) throws TownyException; + /** + * @param group PlotGroup to delete from the Database. + */ + abstract public void deletePlotGroup(PlotGroup group); - abstract public void removeTownBlock(TownBlock townBlock, Cause cause) throws TownyException; + /** + * @param district District to delete from the Database. + */ + abstract public void deleteDistrict(District district); - abstract public void removeTownBlocks(Town town); + /** + * @param resident Resident to delete from the Database. + */ + abstract public void deleteResident(Resident resident); - public boolean removeNation(@NotNull Nation nation, @NotNull DeleteNationEvent.Cause cause) { - return removeNation(nation, cause, null); - } + /** + * @param uuid UUID of the HibernatedResident to delete from the Database. + */ + abstract public void deleteHibernatedResident(UUID uuid); - abstract public boolean removeNation(@NotNull Nation nation, @NotNull DeleteNationEvent.Cause cause, @Nullable CommandSender sender); + /** + * @param town Town to delete from the Database. + */ + abstract public void deleteTown(Town town); /** - * @deprecated Use {@link #newResident(String, UUID)} instead. + * @param nation Nation to delete from the Database. */ - @Deprecated(since = "0.102.0.4") - abstract public @NotNull Resident newResident(String name) throws AlreadyRegisteredException, NotRegisteredException; + abstract public void deleteNation(Nation nation); + + /** + * @param world TownyWorld to delete from the Database. + */ + abstract public void deleteWorld(TownyWorld world); - abstract public @NotNull Resident newResident(String name, UUID uuid) throws AlreadyRegisteredException, NotRegisteredException; - /** - * @deprecated Use {@link #newNation(String, UUID)} instead. + * @param townBlock TownBlock to delete from the Database. + */ + abstract public void deleteTownBlock(TownBlock townBlock); + + /* + * Used in TownyDatabaseHandler. + */ + abstract public void deleteFile(String file); + + /* + * PlotBlockData methods found in TownyDatabaseHandler (used by Flatfile and SQL Sources.) */ - @Deprecated(since = "0.102.0.4") - abstract public void newNation(String name) throws AlreadyRegisteredException, NotRegisteredException; - abstract public void newNation(String name, UUID uuid) throws AlreadyRegisteredException, NotRegisteredException; + abstract public boolean savePlotData(PlotBlockData plotChunk); + + abstract public PlotBlockData loadPlotData(String worldName, int x, int z); + + abstract public PlotBlockData loadPlotData(TownBlock townBlock); + + abstract public boolean hasPlotData(TownBlock townBlock); + + abstract public void deletePlotData(PlotBlockData plotChunk); + + /* + * Remove Object methods found in TownyDatabaseHandler + */ + + abstract public void removeResident(Resident resident); + + abstract public void removeTownBlock(TownBlock townBlock) throws TownyException; - abstract public void newWorld(String name) throws AlreadyRegisteredException; + abstract public void removeTownBlock(TownBlock townBlock, Cause cause) throws TownyException; + + abstract public void removeTownBlocks(Town town); public boolean removeTown(Town town, @NotNull DeleteTownEvent.Cause cause) { return removeTown(town, cause, null); @@ -385,48 +662,307 @@ public boolean removeTown(@NotNull Town town, @NotNull DeleteTownEvent.Cause cau abstract public boolean removeTown(@NotNull Town town, @NotNull DeleteTownEvent.Cause cause, @Nullable CommandSender sender, boolean delayFullRemoval); + public boolean removeNation(@NotNull Nation nation, @NotNull DeleteNationEvent.Cause cause) { + return removeNation(nation, cause, null); + } + + abstract public boolean removeNation(@NotNull Nation nation, @NotNull DeleteNationEvent.Cause cause, @Nullable CommandSender sender); + abstract public void removeWorld(TownyWorld world) throws UnsupportedOperationException; abstract public void removeJail(Jail jail); - + abstract public void removePlotGroup(PlotGroup group); - - abstract public void removeDistrict(District district); + abstract public void removeDistrict(District district); + + /* + * Rename Object methods found in TownyDatabaseHandler + */ + abstract public void renameTown(Town town, String newName) throws AlreadyRegisteredException, NotRegisteredException; abstract public void renameNation(Nation nation, String newName) throws AlreadyRegisteredException, NotRegisteredException; - - abstract public void mergeNation(Nation succumbingNation, Nation prevailingNation); - abstract public void mergeTown(Town mergeInto, Town mergeFrom); + abstract public void renameGroup(PlotGroup group, String newName) throws AlreadyRegisteredException; + + abstract public void renameDistrict(District district, String newName) throws AlreadyRegisteredException; abstract public void renamePlayer(Resident resident, String newName) throws AlreadyRegisteredException, NotRegisteredException; - abstract public void renameGroup(PlotGroup group, String newName) throws AlreadyRegisteredException; - - abstract public void renameDistrict(District district, String newName) throws AlreadyRegisteredException; - - /** - * @deprecated since 0.100.2.9 use {@link #removeTown(Town, com.palmergames.bukkit.towny.event.DeleteTownEvent.Cause)} instead. - * @param town + /* + * Misc */ - @Deprecated - public void removeTown(Town town) { - removeTown(town, DeleteTownEvent.Cause.UNKNOWN); - } - - @SuppressWarnings("unused") - private void removeTown$$bridge$$public(Town town, boolean delayFullRemoval) { - removeTown(town, DeleteTownEvent.Cause.UNKNOWN, null, delayFullRemoval); - } + + abstract public void mergeNation(Nation succumbingNation, Nation prevailingNation); + + abstract public void mergeTown(Town mergeInto, Town mergeFrom); /** - * @deprecated since 0.100.2.96 use {@link #removeNation(Nation, com.palmergames.bukkit.towny.event.DeleteNationEvent.Cause)} instead. - * @param nation + * @param uuid UUID of the HibernatedResident + * @return a CompletableFuture that should result in the Long value representing + * the resident's registered time. */ - @Deprecated - public void removeNation(Nation nation) { - removeNation(nation, DeleteNationEvent.Cause.UNKNOWN, null); + abstract public CompletableFuture> getHibernatedResidentRegistered(UUID uuid); + + public boolean cleanup() { + + return true; + } + +// /** +// * OLD STUFF +// */ + +// +// public boolean loadResidents() { +// +// TownyMessaging.sendDebugMsg("Loading Residents"); +// +// for (Resident resident : universe.getResidents()) { +// if (!loadResident(resident)) { +// plugin.getLogger().severe("Loading Error: Could not read resident data '" + resident.getName() + "'."); +// return false; +// } +// } +// return true; +// } +// +// public boolean loadTowns() { +// +// TownyMessaging.sendDebugMsg("Loading Towns"); +// for (Town town : universe.getTowns()) +// if (!loadTown(town)) { +// plugin.getLogger().severe("Loading Error: Could not read town data '" + town.getName() + "'."); +// return false; +// } +// return true; +// } +// +// public boolean loadNations() { +// +// TownyMessaging.sendDebugMsg("Loading Nations"); +// for (Nation nation : universe.getNations()) +// if (!loadNation(nation)) { +// plugin.getLogger().severe("Loading Error: Could not read nation data '" + nation.getName() + "'."); +// return false; +// } +// return true; +// } +// +// public boolean loadWorlds() { +// +// TownyMessaging.sendDebugMsg("Loading Worlds"); +// for (TownyWorld world : universe.getTownyWorlds()) +// if (!loadWorld(world)) { +// plugin.getLogger().severe("Loading Error: Could not read world data '" + world.getName() + "'."); +// return false; +// } +// return true; +// } +// +// public boolean loadJails() { +// TownyMessaging.sendDebugMsg("Loading Jails"); +// for (Jail jail : universe.getJails()) { +// if (!loadJail(jail)) { +// plugin.getLogger().severe("Loading Error: Could not read jail data '" + jail.getUUID() + "'."); +// return false; +// } +// } +// return true; +// } +// +// public boolean loadPlotGroups() { +// TownyMessaging.sendDebugMsg("Loading PlotGroups"); +// for (PlotGroup group : universe.getGroups()) { +// if (!loadPlotGroup(group)) { +// plugin.getLogger().severe("Loading Error: Could not read PlotGroup data: '" + group.getUUID() + "'."); +// return false; +// } +// } +// return true; +// } +// +// public boolean loadDistricts() { +// TownyMessaging.sendDebugMsg("Loading Districts"); +// for (District district : universe.getDistricts()) { +// if (!loadDistrict(district)) { +// plugin.getLogger().severe("Loading Error: Could not read District data: '" + district.getUUID() + "'."); +// return false; +// } +// } +// return true; +// } +// +// abstract public boolean loadCooldowns(); +// +// /* +// * Save all of category +// */ +// +// public boolean saveResidents() { +// +// TownyMessaging.sendDebugMsg("Saving Residents"); +// for (Resident resident : universe.getResidents()) +// saveResident(resident); +// return true; +// } +// +// public boolean savePlotGroups() { +// TownyMessaging.sendDebugMsg("Saving PlotGroups"); +// for (PlotGroup plotGroup : universe.getGroups()) +// /* +// * Only save plotgroups which actually have townblocks associated with them. +// */ +// if (plotGroup.hasTownBlocks()) +// savePlotGroup(plotGroup); +// else +// deletePlotGroup(plotGroup); +// return true; +// } +// +// public boolean saveDistricts() { +// TownyMessaging.sendDebugMsg("Saving Districts"); +// for (District district : universe.getDistricts()) +// /* +// * Only save districts which actually have townblocks associated with them. +// */ +// if (district.hasTownBlocks()) +// saveDistrict(district); +// else +// deleteDistrict(district); +// return true; +// } +// +// public boolean saveJails() { +// TownyMessaging.sendDebugMsg("Saving Jails"); +// for (Jail jail : universe.getJails()) +// saveJail(jail); +// return true; +// } +// +// public boolean saveTowns() { +// +// TownyMessaging.sendDebugMsg("Saving Towns"); +// for (Town town : universe.getTowns()) +// saveTown(town); +// return true; +// } +// +// public boolean saveNations() { +// +// TownyMessaging.sendDebugMsg("Saving Nations"); +// for (Nation nation : universe.getNations()) +// saveNation(nation); +// return true; +// } +// +// public boolean saveWorlds() { +// +// TownyMessaging.sendDebugMsg("Saving Worlds"); +// for (TownyWorld world : universe.getTownyWorlds()) +// saveWorld(world); +// return true; +// } +// +// public boolean saveTownBlocks() { +// TownyMessaging.sendDebugMsg("Saving Townblocks"); +// for (Town town : universe.getTowns()) { +// for (TownBlock townBlock : town.getTownBlocks()) +// saveTownBlock(townBlock); +// } +// return true; +// } +// +// abstract public boolean saveCooldowns(); +// +// // Database functions +// +// abstract public void removeResident(Resident resident); +// +// abstract public void removeTownBlock(TownBlock townBlock) throws TownyException; +// +// abstract public void removeTownBlock(TownBlock townBlock, Cause cause) throws TownyException; +// +// abstract public void removeTownBlocks(Town town); +// +// public boolean removeNation(@NotNull Nation nation, @NotNull DeleteNationEvent.Cause cause) { +// return removeNation(nation, cause, null); +// } +// +// abstract public boolean removeNation(@NotNull Nation nation, @NotNull DeleteNationEvent.Cause cause, @Nullable CommandSender sender); +// +// /** +// * @deprecated Use {@link #newResident(String, UUID)} instead. +// */ +// @Deprecated(since = "0.102.0.4") +// abstract public @NotNull Resident newResident(String name) throws AlreadyRegisteredException, NotRegisteredException; +// +// abstract public @NotNull Resident newResident(String name, UUID uuid) throws AlreadyRegisteredException, NotRegisteredException; +// +// /** +// * @deprecated Use {@link #newNation(String, UUID)} instead. +// */ +// @Deprecated(since = "0.102.0.4") +// abstract public void newNation(String name) throws AlreadyRegisteredException, NotRegisteredException; +// +// abstract public void newNation(String name, UUID uuid) throws AlreadyRegisteredException, NotRegisteredException; +// +// abstract public void newWorld(String name) throws AlreadyRegisteredException; +// +// public boolean removeTown(Town town, @NotNull DeleteTownEvent.Cause cause) { +// return removeTown(town, cause, null); +// } +// +// public boolean removeTown(@NotNull Town town, @NotNull DeleteTownEvent.Cause cause, @Nullable CommandSender sender) { +// return removeTown(town, cause, sender, TownySettings.getTownRuinsEnabled() && !town.isRuined()); +// } +// +// abstract public boolean removeTown(@NotNull Town town, @NotNull DeleteTownEvent.Cause cause, @Nullable CommandSender sender, boolean delayFullRemoval); +// +// abstract public void removeWorld(TownyWorld world) throws UnsupportedOperationException; +// +// abstract public void removeJail(Jail jail); +// +// abstract public void removePlotGroup(PlotGroup group); +// +// abstract public void removeDistrict(District district); +// +// abstract public void renameTown(Town town, String newName) throws AlreadyRegisteredException, NotRegisteredException; +// +// abstract public void renameNation(Nation nation, String newName) throws AlreadyRegisteredException, NotRegisteredException; +// +// abstract public void mergeNation(Nation succumbingNation, Nation prevailingNation); +// +// abstract public void mergeTown(Town mergeInto, Town mergeFrom); +// +// abstract public void renamePlayer(Resident resident, String newName) throws AlreadyRegisteredException, NotRegisteredException; +// +// abstract public void renameGroup(PlotGroup group, String newName) throws AlreadyRegisteredException; +// +// abstract public void renameDistrict(District district, String newName) throws AlreadyRegisteredException; +// +// /** +// * @deprecated since 0.100.2.9 use {@link #removeTown(Town, com.palmergames.bukkit.towny.event.DeleteTownEvent.Cause)} instead. +// * @param town +// */ +// @Deprecated +// public void removeTown(Town town) { +// removeTown(town, DeleteTownEvent.Cause.UNKNOWN); +// } +// +// @SuppressWarnings("unused") +// private void removeTown$$bridge$$public(Town town, boolean delayFullRemoval) { +// removeTown(town, DeleteTownEvent.Cause.UNKNOWN, null, delayFullRemoval); +// } +// +// /** +// * @deprecated since 0.100.2.96 use {@link #removeNation(Nation, com.palmergames.bukkit.towny.event.DeleteNationEvent.Cause)} instead. +// * @param nation +// */ +// @Deprecated +// public void removeNation(Nation nation) { +// removeNation(nation, DeleteNationEvent.Cause.UNKNOWN, null); +// } } diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/db/TownyDatabaseHandler.java b/Towny/src/main/java/com/palmergames/bukkit/towny/db/TownyDatabaseHandler.java index d1eb789f6a5..726d02f5628 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/db/TownyDatabaseHandler.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/db/TownyDatabaseHandler.java @@ -1,11 +1,11 @@ package com.palmergames.bukkit.towny.db; -import com.google.common.base.Preconditions; import com.palmergames.bukkit.towny.Towny; import com.palmergames.bukkit.towny.TownyEconomyHandler; import com.palmergames.bukkit.towny.TownyMessaging; import com.palmergames.bukkit.towny.TownySettings; import com.palmergames.bukkit.towny.TownyUniverse; +import com.palmergames.bukkit.towny.db.TownyFlatFileSource.TownyDBFileType; import com.palmergames.bukkit.towny.db.TownyFlatFileSource.elements; import com.palmergames.bukkit.towny.event.DeleteNationEvent; import com.palmergames.bukkit.towny.event.DeletePlayerEvent; @@ -23,11 +23,12 @@ import com.palmergames.bukkit.towny.exceptions.EmptyTownException; import com.palmergames.bukkit.towny.exceptions.InvalidNameException; import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; +import com.palmergames.bukkit.towny.exceptions.ObjectCouldNotBeLoadedException; +import com.palmergames.bukkit.towny.exceptions.ObjectSaveException; import com.palmergames.bukkit.towny.exceptions.TownyException; import com.palmergames.bukkit.towny.invites.Invite; import com.palmergames.bukkit.towny.invites.InviteHandler; import com.palmergames.bukkit.towny.object.District; -import com.palmergames.bukkit.towny.object.Identifiable; import com.palmergames.bukkit.towny.object.Nation; import com.palmergames.bukkit.towny.object.PlotGroup; import com.palmergames.bukkit.towny.object.Resident; @@ -57,6 +58,8 @@ import com.palmergames.bukkit.util.NameValidation; import com.palmergames.util.FileMgmt; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import com.palmergames.util.JavaUtil; import com.palmergames.util.Pair; import org.bukkit.Bukkit; @@ -79,8 +82,10 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Queue; import java.util.Random; import java.util.UUID; @@ -90,7 +95,7 @@ import java.util.zip.ZipFile; /** - * @author ElgarL + * @author ElgarL, LlmDl */ public abstract class TownyDatabaseHandler extends TownyDataSource { public static final SimpleDateFormat BACKUP_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH_mm_ssZ"); @@ -99,6 +104,8 @@ public abstract class TownyDatabaseHandler extends TownyDataSource { final String settingsFolderPath; final String logFolderPath; final String backupFolderPath; + + Logger logger = LogManager.getLogger(TownyDatabaseHandler.class); protected final Queue queryQueue = new ConcurrentLinkedQueue<>(); private final ScheduledTask task; protected List> pendingDuplicateResidents = new ArrayList<>(); @@ -124,7 +131,7 @@ protected TownyDatabaseHandler(Towny plugin, TownyUniverse universe) { } /* - * Start our async queue for pushing data to the database. + * Start our async queue for pushing data to the flatfile database. */ task = plugin.getScheduler().runAsyncRepeating(() -> { synchronized(queryQueue) { @@ -138,7 +145,7 @@ protected TownyDatabaseHandler(Towny plugin, TownyUniverse universe) { @Override public void finishTasks() { - + // Cancel the repeating task as its not needed anymore. synchronized (this.queryQueue) { if (task != null) @@ -151,7 +158,7 @@ public void finishTasks() { } } } - + @Override public boolean backup() throws IOException { @@ -166,28 +173,28 @@ public boolean backup() throws IOException { String backupType = TownySettings.getFlatFileBackupType(); String newBackupFolder = backupFolderPath + File.separator + BACKUP_DATE_FORMAT.format(System.currentTimeMillis()); FileMgmt.checkOrCreateFolders(rootFolderPath, rootFolderPath + File.separator + "backup"); - return switch (backupType.toLowerCase(Locale.ROOT)) { - case "folder" -> { - FileMgmt.checkOrCreateFolder(newBackupFolder); - FileMgmt.copyDirectory(new File(dataFolderPath), new File(newBackupFolder)); - FileMgmt.copyDirectory(new File(logFolderPath), new File(newBackupFolder)); - FileMgmt.copyDirectory(new File(settingsFolderPath), new File(newBackupFolder)); - yield true; - } - case "zip" -> { - FileMgmt.zipDirectories(new File(newBackupFolder + ".zip"), new File(dataFolderPath), - new File(logFolderPath), new File(settingsFolderPath)); - yield true; - } - case "tar.gz", "tar" -> { - FileMgmt.tar(new File(newBackupFolder.concat(".tar.gz")), - new File(dataFolderPath), - new File(logFolderPath), - new File(settingsFolderPath)); - yield true; - } - default -> false; - }; + return switch (backupType.toLowerCase(Locale.ROOT)) { + case "folder" -> { + FileMgmt.checkOrCreateFolder(newBackupFolder); + FileMgmt.copyDirectory(new File(dataFolderPath), new File(newBackupFolder)); + FileMgmt.copyDirectory(new File(logFolderPath), new File(newBackupFolder)); + FileMgmt.copyDirectory(new File(settingsFolderPath), new File(newBackupFolder)); + yield true; + } + case "zip" -> { + FileMgmt.zipDirectories(new File(newBackupFolder + ".zip"), new File(dataFolderPath), + new File(logFolderPath), new File(settingsFolderPath)); + yield true; + } + case "tar.gz", "tar" -> { + FileMgmt.tar(new File(newBackupFolder.concat(".tar.gz")), + new File(dataFolderPath), + new File(logFolderPath), + new File(settingsFolderPath)); + yield true; + } + default -> false; + }; } @Override @@ -195,118 +202,285 @@ public void postLoad() { deleteDuplicateResidents(); } - private void deleteDuplicateResidents() { - for (final Pair residentPair : this.pendingDuplicateResidents) { - Resident firstRes = universe.getResident(residentPair.left()); - Resident secondRes = universe.getResident(residentPair.right()); + /* + * Load all Objects of each type. + */ - // Check if both uuids are actually equal - if (firstRes == null || secondRes == null || firstRes.getUUID() == null || !firstRes.getUUID().equals(secondRes.getUUID())) { - continue; - } + public boolean loadJails() { + try { + return loadJailUUIDs(universe.getJailUUIDs()); + } catch (ObjectCouldNotBeLoadedException e) { + TownyMessaging.sendErrorMsg(e.getMessage()); + return false; + } + } - if (firstRes.getLastOnline() > secondRes.getLastOnline()) { - // firstRes was online most recently, so delete secondRes - TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_deleting_duplicate", secondRes.getName(), firstRes.getName())); - try { - universe.unregisterResident(secondRes); - } catch (NotRegisteredException ignored) {} - // Check if the older resident is a part of a town - Town olderResTown = secondRes.getTownOrNull(); - if (olderResTown != null) { - try { - // Resident#removeTown saves the resident, so we can't use it. - olderResTown.removeResident(secondRes); - } catch (EmptyTownException e) { - try { - universe.unregisterTown(olderResTown); - } catch (NotRegisteredException ignored) {} - deleteTown(olderResTown); - } - } - deleteResident(secondRes); - } else { - TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_deleting_duplicate", firstRes.getName(), secondRes.getName())); - try { - universe.unregisterResident(firstRes); - } catch (NotRegisteredException ignored) {} - deleteResident(firstRes); - } + public boolean loadPlotGroups() { + try { + return loadPlotGroupUUIDs(universe.getPlotGroupUUIDs()); + } catch (ObjectCouldNotBeLoadedException e) { + TownyMessaging.sendErrorMsg(e.getMessage()); + return false; } + } - this.pendingDuplicateResidents.clear(); + public boolean loadDistricts() { + try { + return loadDistrictUUIDs(universe.getDistrictUUIDs()); + } catch (ObjectCouldNotBeLoadedException e) { + TownyMessaging.sendErrorMsg(e.getMessage()); + return false; + } + } + + public boolean loadResidents() { + try { + return loadResidentUUIDs(universe.getResidentUUIDs()); + } catch (ObjectCouldNotBeLoadedException e) { + TownyMessaging.sendErrorMsg(e.getMessage()); + return false; + } + } + + public boolean loadTowns() { + try { + return loadTownUUIDs(universe.getTownUUIDs()); + } catch (ObjectCouldNotBeLoadedException e) { + TownyMessaging.sendErrorMsg(e.getMessage()); + return false; + } + } + + public boolean loadNations() { + try { + return loadNationUUIDs(universe.getNationUUIDs()); + } catch (ObjectCouldNotBeLoadedException e) { + TownyMessaging.sendErrorMsg(e.getMessage()); + return false; + } + } + + public boolean loadWorlds() { + try { + return loadWorldUUIDs(universe.getWorldUUIDs()); + } catch (ObjectCouldNotBeLoadedException e) { + TownyMessaging.sendErrorMsg(e.getMessage()); + return false; + } + } + + public boolean loadTownBlocks() { + try { + return loadTownBlocks(universe.getTownBlocks().values()); + } catch (ObjectCouldNotBeLoadedException e) { + TownyMessaging.sendErrorMsg(e.getMessage()); + return false; + } } /* - * Add new objects to the TownyUniverse maps. + * Object loading methods which pull Maps from FlatFile/SQLSources */ - - @Override - public @NotNull Resident newResident(String name) throws AlreadyRegisteredException, NotRegisteredException { - final UUID uuid = this.parsePlayerUUID(null, name); - if (uuid == null) { - throw new NotRegisteredException("Could not find a uuid for player name '" + name + "'."); + + public boolean loadJailData(UUID uuid) { + Jail jail = TownyUniverse.getInstance().getJail(uuid); + if (jail == null) { + TownyMessaging + .sendErrorMsg("Cannot find a jail with the UUID " + uuid.toString() + " in the TownyUniverse."); + return false; } + Map jailAsMap = getJailMap(uuid); + if (jailAsMap == null) + return false; + return jail.load(jailAsMap); + } - return newResident(name, uuid); + public boolean loadPlotGroupData(UUID uuid) { + PlotGroup plotGroup = TownyUniverse.getInstance().getGroup(uuid); + if (plotGroup == null) { + TownyMessaging.sendErrorMsg( + "Cannot find a plotgroup with the UUID " + uuid.toString() + " in the TownyUniverse."); + return false; + } + Map groupAsMap = getPlotGroupMap(uuid); + if (groupAsMap == null) + return false; + return plotGroup.load(groupAsMap); } - @Override - public @NotNull Resident newResident(String name, UUID uuid) throws AlreadyRegisteredException, NotRegisteredException { - Preconditions.checkArgument(name != null, "name may not be null"); - Preconditions.checkArgument(uuid != null, "uuid may not be null"); + public boolean loadDistrictData(UUID uuid) { + District district = TownyUniverse.getInstance().getDistrict(uuid); + if (district == null) { + TownyMessaging.sendErrorMsg( + "Cannot find a district with the UUID " + uuid.toString() + " in the TownyUniverse."); + return false; + } + Map districtAsMap = getDistrictMap(uuid); + if (districtAsMap == null) + return false; + return district.load(districtAsMap); + } + + public boolean loadResidentData(UUID uuid) { + Resident resident = TownyUniverse.getInstance().getResident(uuid); + if (resident == null) { + TownyMessaging.sendErrorMsg("Cannot find a resident with the UUID " + uuid.toString() + " in the TownyUniverse."); + return false; + } + Map residentAsMap = getResidentMap(uuid); + if (residentAsMap == null) + return false; + return resident.load(residentAsMap); + } + + public boolean loadTownData(UUID uuid) { + Town town = TownyUniverse.getInstance().getTown(uuid); + if (town == null) { + TownyMessaging + .sendErrorMsg("Cannot find a town with the UUID " + uuid.toString() + " in the TownyUniverse."); + return false; + } + Map townAsMap = getTownMap(uuid); + if (townAsMap == null) + return false; + return town.load(townAsMap); + } + + public boolean loadNationData(UUID uuid) { + Nation nation = TownyUniverse.getInstance().getNation(uuid); + if (nation == null) { + TownyMessaging + .sendErrorMsg("Cannot find a nation with the UUID " + uuid.toString() + " in the TownyUniverse."); + return false; + } + Map nationAsMap = getNationMap(uuid); + if (nationAsMap == null) + return false; + return nation.load(nationAsMap); + } + + public boolean loadWorldData(UUID uuid) { + TownyWorld world = TownyUniverse.getInstance().getWorld(uuid); + if (world == null) { + TownyMessaging + .sendErrorMsg("Cannot find a world with the UUID " + uuid.toString() + " in the TownyUniverse."); + return false; + } + Map worldAsMap = getWorldMap(uuid); + if (worldAsMap == null) + return false; + return world.load(worldAsMap); + } - String filteredName; + public boolean loadTownBlock(TownBlock townBlock) { + Map townBlockAsMap = getTownBlockMap(townBlock); + if (townBlockAsMap == null) + return false; + return townBlock.load(townBlockAsMap); + } + + /* + * Save Object Methods that call Flatfile/SQLSources after gathering the objects + * as Maps. + */ + + public boolean saveJail(Jail jail) { try { - filteredName = NameValidation.checkAndFilterPlayerName(name); - } catch (InvalidNameException e) { - throw new NotRegisteredException(e.getMessage()); + return saveJail(jail, jail.getObjectDataMap()); + } catch (ObjectSaveException e) { + logger.warn(e.getMessage(), e); + return false; } - - if (universe.hasResident(name)) - throw new AlreadyRegisteredException("A resident with the name " + filteredName + " is already in use."); - - Resident resident = new Resident(filteredName, uuid); - - universe.registerResident(resident); - return resident; } - @Override - public void newNation(String name) throws AlreadyRegisteredException, NotRegisteredException { - newNation(name, UUID.randomUUID()); + public boolean savePlotGroup(PlotGroup group) { + try { + return savePlotGroup(group, group.getObjectDataMap()); + } catch (ObjectSaveException e) { + logger.warn(e.getMessage(), e); + return false; + } } - @Override - public void newNation(String name, @NotNull UUID uuid) throws AlreadyRegisteredException, NotRegisteredException { - String filteredName; + public boolean saveDistrict(District district) { try { - filteredName = NameValidation.checkAndFilterNationNameOrThrow(name); - } catch (InvalidNameException e) { - throw new NotRegisteredException(e.getMessage()); + return saveDistrict(district, district.getObjectDataMap()); + } catch (ObjectSaveException e) { + logger.warn(e.getMessage(), e); + return false; } + } - if (universe.hasNation(filteredName)) - throw new AlreadyRegisteredException("The nation " + filteredName + " is already in use."); + public boolean saveResident(Resident resident) { + try { + return saveResident(resident, resident.getObjectDataMap()); + } catch (ObjectSaveException e) { + logger.warn(e.getMessage(), e); + return false; + } + } - Nation nation = new Nation(filteredName, uuid); - - universe.registerNation(nation); + public boolean saveHibernatedResident(UUID uuid, long registered) { + Map res_hm = new HashMap<>(); + res_hm.put("registered", registered); + return saveHibernatedResident(uuid, res_hm); } - @Override - public void newWorld(String name) throws AlreadyRegisteredException { - - if (universe.getWorldMap().containsKey(name.toLowerCase(Locale.ROOT))) - throw new AlreadyRegisteredException("The world " + name + " is already in use."); + public boolean saveTown(Town town) { + try { + return saveTown(town, town.getObjectDataMap()); + } catch (ObjectSaveException e) { + logger.warn(e.getMessage(), e); + return false; + } + } + + public boolean saveNation(Nation nation) { + try { + return saveNation(nation, nation.getObjectDataMap()); + } catch (ObjectSaveException e) { + logger.warn(e.getMessage(), e); + return false; + } + } - universe.getWorldMap().put(name.toLowerCase(Locale.ROOT), new TownyWorld(name)); + public boolean saveWorld(TownyWorld world) { + try { + return saveWorld(world, world.getObjectDataMap()); + } catch (ObjectSaveException e) { + logger.warn(e.getMessage(), e); + return false; + } + } + + public boolean saveTownBlock(TownBlock townBlock) { + try { + return saveTownBlock(townBlock, townBlock.getObjectDataMap()); + } catch (ObjectSaveException e) { + logger.warn(e.getMessage(), e); + return false; + } } /* * Remove Object Methods */ - + + protected void removeFromUniverse(TownyDBFileType type, UUID uuid) { + switch (type) { + case JAIL -> universe.unregisterJail(uuid); + case NATION -> universe.unregisterNation(uuid); + case PLOTGROUP -> universe.unregisterGroup(uuid); + case DISTRICT -> universe.unregisterDistrict(uuid); + case RESIDENT -> universe.unregisterResident(uuid); + case TOWN -> universe.unregisterTown(uuid); + case TOWNBLOCK -> throw new UnsupportedOperationException("Unimplemented case: " + type); + case WORLD -> throw new UnsupportedOperationException("Unimplemented case: " + type); + default -> throw new IllegalArgumentException("Unexpected value: " + type); + } + ; + } + @Override public void removeResident(Resident resident) { @@ -379,11 +553,7 @@ public void removeResident(Resident resident) { // Delete the residents file. deleteResident(resident); // Remove the residents record from memory. - try { - universe.unregisterResident(resident); - } catch (NotRegisteredException e) { - plugin.getLogger().log(Level.WARNING, "An exception occurred while unregistering resident " + resident.getName(), e); - } + removeFromUniverse(TownyDBFileType.RESIDENT, resident.getUUID()); // Clear accounts if (TownySettings.isDeleteEcoAccount() && TownyEconomyHandler.isActive()) @@ -506,13 +676,7 @@ public boolean removeTown(@NotNull Town town, @NotNull DeleteTownEvent.Cause cau } saveWorld(townyWorld); } - - try { - universe.unregisterTown(town); - } catch (NotRegisteredException e) { - TownyMessaging.sendErrorMsg(e.getMessage()); - } - + removeFromUniverse(TownyDBFileType.TOWN, town.getUUID()); plugin.resetCache(); deleteTown(town); @@ -609,6 +773,7 @@ public boolean removeNation(@NotNull Nation nation, @NotNull DeleteNationEvent.C BukkitTools.fireEvent(new NationRemoveTownEvent(town, nation)); } + removeFromUniverse(TownyDBFileType.NATION, nation.getUUID()); plugin.resetCache(); BukkitTools.fireEvent(new DeleteNationEvent(nation, king, cause, sender)); @@ -638,20 +803,20 @@ public void removeJail(Jail jail) { jail.getTown().removeJail(jail); // Unregister the jail from the Universe. - universe.unregisterJail(jail); - + removeFromUniverse(TownyDBFileType.JAIL, jail.getUUID()); + deleteJail(jail); } @Override public void removePlotGroup(PlotGroup group) { - universe.unregisterGroup(group.getUUID()); + removeFromUniverse(TownyDBFileType.PLOTGROUP, group.getUUID()); deletePlotGroup(group); } @Override public void removeDistrict(District district) { - universe.unregisterDistrict(district.getUUID()); + removeFromUniverse(TownyDBFileType.DISTRICT, district.getUUID()); deleteDistrict(district); } @@ -817,7 +982,7 @@ public void renamePlayer(Resident resident, String newName) throws AlreadyRegist // Remove the resident from the universe name storage. universe.unregisterResident(resident); - //rename the resident + // Rename the resident resident.setName(newName); // Re-register the resident with the new name. universe.registerResident(resident); @@ -1179,32 +1344,6 @@ public void mergeTown(Town mergeInto, Town mergeFrom) { mergeInto.save(); TownyMessaging.sendGlobalMessage(Translatable.of("msg_town_merge_success", mergeFrom.getName(), mayorName, mergeInto.getName())); } - - protected List toUUIDList(Collection objects) { - final List list = new ArrayList<>(); - - for (final Identifiable object : objects) { - final UUID uuid = object.getUUID(); - - if (uuid != null) { - list.add(uuid); - } - } - - return list; - } - - public UUID[] toUUIDArray(String[] uuidArray) { - final List uuids = new ArrayList<>(); - - for (final String uuid : uuidArray) { - try { - uuids.add(UUID.fromString(uuid)); - } catch (IllegalArgumentException ignored) {} - } - - return uuids.toArray(new UUID[0]); - } /** * Generates a town or nation replacementname. @@ -1294,4 +1433,56 @@ protected UUID parseUUIDOrNew(@Nullable String uuidString, String describedAs) { plugin.getLogger().warning("Could not find a previous UUID for player '" + playerName + "', looking it up using the Mojang API..."); return plugin.getServer().getPlayerUniqueId(playerName); } + + private void deleteDuplicateResidents() { + for (final Pair residentPair : this.pendingDuplicateResidents) { + Resident firstRes = universe.getResident(residentPair.left()); + Resident secondRes = universe.getResident(residentPair.right()); + + // Check if both uuids are actually equal + if (firstRes == null || secondRes == null || firstRes.getUUID() == null || !firstRes.getUUID().equals(secondRes.getUUID())) { + continue; + } + + if (firstRes.getLastOnline() > secondRes.getLastOnline()) { + // firstRes was online most recently, so delete secondRes + TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_deleting_duplicate", secondRes.getName(), firstRes.getName())); + try { + // We don't know which Resident is tied to the UUID stored in the TownyUniverse + // residentUUIDMap, so we remove both and re-register the last resident to log + // in. + universe.unregisterResident(secondRes); + universe.unregisterResident(firstRes); + universe.registerResident(firstRes); + } catch (NotRegisteredException | AlreadyRegisteredException ignored) {} + // Check if the older resident is a part of a town + Town olderResTown = secondRes.getTownOrNull(); + if (olderResTown != null) { + try { + // Resident#removeTown saves the resident, so we can't use it. + olderResTown.removeResident(secondRes); + } catch (EmptyTownException e) { + try { + universe.unregisterTown(olderResTown); + } catch (NotRegisteredException ignored) {} + deleteTown(olderResTown); + } + } + deleteResident(secondRes); + } else { + TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_deleting_duplicate", firstRes.getName(), secondRes.getName())); + try { + // We don't know which Resident is tied to the UUID stored in the TownyUniverse + // residentUUIDMap, so we remove both and re-register the last resident to log + // in. + universe.unregisterResident(firstRes); + universe.unregisterResident(secondRes); + universe.registerResident(secondRes); + } catch (NotRegisteredException | AlreadyRegisteredException ignored) {} + deleteResident(firstRes); + } + } + + this.pendingDuplicateResidents.clear(); + } } diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/db/TownyFlatFileSource.java b/Towny/src/main/java/com/palmergames/bukkit/towny/db/TownyFlatFileSource.java index c7e6692ddb7..b9a4c681ee3 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/db/TownyFlatFileSource.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/db/TownyFlatFileSource.java @@ -6,73 +6,49 @@ import com.google.gson.JsonSyntaxException; import com.google.gson.reflect.TypeToken; import com.palmergames.bukkit.towny.Towny; -import com.palmergames.bukkit.towny.TownyAPI; import com.palmergames.bukkit.towny.TownyMessaging; import com.palmergames.bukkit.towny.TownySettings; import com.palmergames.bukkit.towny.TownyUniverse; -import com.palmergames.bukkit.towny.event.DeleteTownEvent; -import com.palmergames.bukkit.towny.event.DeleteNationEvent; -import com.palmergames.bukkit.towny.exceptions.AlreadyRegisteredException; -import com.palmergames.bukkit.towny.exceptions.EmptyNationException; -import com.palmergames.bukkit.towny.exceptions.InvalidNameException; import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; -import com.palmergames.bukkit.towny.exceptions.TownyException; +import com.palmergames.bukkit.towny.exceptions.ObjectCouldNotBeLoadedException; import com.palmergames.bukkit.towny.object.District; import com.palmergames.bukkit.towny.object.NameAndId; import com.palmergames.bukkit.towny.object.Nation; -import com.palmergames.bukkit.towny.object.PermissionData; import com.palmergames.bukkit.towny.object.PlotGroup; -import com.palmergames.bukkit.towny.object.Position; import com.palmergames.bukkit.towny.object.Resident; import com.palmergames.bukkit.towny.object.Town; import com.palmergames.bukkit.towny.object.TownBlock; -import com.palmergames.bukkit.towny.object.TownBlockTypeHandler; import com.palmergames.bukkit.towny.object.TownyWorld; import com.palmergames.bukkit.towny.object.Translation; -import com.palmergames.bukkit.towny.object.WorldCoord; -import com.palmergames.bukkit.towny.object.metadata.MetadataLoader; import com.palmergames.bukkit.towny.object.jail.Jail; import com.palmergames.bukkit.towny.tasks.CooldownTimerTask; import com.palmergames.bukkit.towny.tasks.DeleteFileTask; -import com.palmergames.bukkit.towny.utils.MapUtil; import com.palmergames.bukkit.util.BukkitTools; import com.palmergames.util.FileMgmt; -import com.palmergames.util.JavaUtil; import com.palmergames.util.Pair; -import com.palmergames.util.StringMgmt; + import org.bukkit.Bukkit; import org.bukkit.World; -import org.jetbrains.annotations.Nullable; - -import java.io.BufferedReader; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; -import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; +import java.util.Collection; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; import java.util.logging.Level; -import java.util.stream.Collectors; import java.util.stream.Stream; public final class TownyFlatFileSource extends TownyDatabaseHandler { private static final int UUID_LENGTH = 36; - private final String newLine = System.lineSeparator(); - public TownyFlatFileSource(Towny plugin, TownyUniverse universe) { super(plugin, universe); // Create files and folders if non-existent @@ -113,2615 +89,557 @@ public static elements fromString(String str) { } } - public String getResidentFilename(Resident resident) { + public enum TownyDBFileType { + ALLIANCE("alliances", ".txt"), NATION("nations", ".txt"), TOWN("towns", ".txt"), RESIDENT("residents", ".txt"), + HIBERNATED_RESIDENT("residents" + File.separator + "hibernated", ".txt"), JAIL("jails", ".txt"), + WORLD("worlds", ".txt"), TOWNBLOCK("townblocks", ".data"), PLOTGROUP("plotgroups", ".data"), DISTRICT("districts", ".data"); - return dataFolderPath + File.separator + "residents" + File.separator + resident.getUUID() + ".txt"; - } - - public String getHibernatedResidentFilename(UUID uuid) { + String folderName; + String fileExtension; - return dataFolderPath + File.separator + "residents" + File.separator + "hibernated" + File.separator + uuid + ".txt"; - } + TownyDBFileType(String folderName, String fileExtension) { + this.folderName = folderName; + this.fileExtension = fileExtension; + } - public String getTownFilename(Town town) { + private String getSingular() { + // Hibernated Residents are never loaded so this method is never called on them. + return folderName.substring(0, folderName.length() - 1); + } - return dataFolderPath + File.separator + "towns" + File.separator + town.getUUID() + ".txt"; - } + public String getFolderName() { + return folderName; + } - public String getNationFilename(Nation nation) { + public String getSaveLocation(String fileName) { + return Towny.getPlugin().getDataFolder().getPath() + File.separator + "data" + File.separator + folderName + + File.separator + fileName + fileExtension; + } - return dataFolderPath + File.separator + "nations" + File.separator + nation.getUUID() + ".txt"; + public String getLoadErrorMsg(UUID uuid) { + return "Loading Error: Could not read the " + getSingular() + " with UUID '" + uuid + "' from the " + + folderName + " folder."; + } } - public String getWorldFilename(TownyWorld world) { - - return dataFolderPath + File.separator + "worlds" + File.separator + world.getName() + ".txt"; + private String getFileOfTypeWithUUID(TownyDBFileType type, UUID uuid) { + return dataFolderPath + File.separator + type.folderName + File.separator + uuid + type.fileExtension; } - public String getTownBlockFilename(TownBlock townBlock) { - - return dataFolderPath + File.separator + "townblocks" + File.separator + townBlock.getWorld().getName() + File.separator + townBlock.getX() + "_" + townBlock.getZ() + "_" + TownySettings.getTownBlockSize() + ".data"; - } - - public String getPlotGroupFilename(PlotGroup group) { - return dataFolderPath + File.separator + "plotgroups" + File.separator + group.getUUID() + ".data"; + private String getFileOfTypeWithName(TownyDBFileType type, String name) { + return dataFolderPath + File.separator + type.folderName + File.separator + name + type.fileExtension; } - public String getDistrictFilename(District district) { - return dataFolderPath + File.separator + "districts" + File.separator + district.getUUID() + ".data"; - } + private boolean loadFlatFileListOfType(TownyDBFileType type, Consumer consumer) { + TownyMessaging.sendDebugMsg("Searching for " + type.folderName + "..."); + File[] files = new File(dataFolderPath + File.separator + type.folderName) + .listFiles(file -> file.getName().toLowerCase().endsWith(type.fileExtension)); - public String getJailFilename(Jail jail) { - return dataFolderPath + File.separator + "jails" + File.separator + jail.getUUID() + ".txt"; - } - - /* - * Load keys - */ - - @Override - public boolean loadTownBlockList() { - - TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_loading_townblock_list")); + if (files.length != 0) + TownyMessaging.sendDebugMsg("Loading " + files.length + " entries from the " + type.folderName + " folder..."); - File townblocksFolder = new File(dataFolderPath + File.separator + "townblocks"); - File[] worldFolders = townblocksFolder.listFiles(File::isDirectory); - TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_folders_found", worldFolders.length)); - boolean mismatched = false; - int mismatchedCount = 0; - try { - for (File worldfolder : worldFolders) { - String worldName = worldfolder.getName(); - if (BukkitTools.getWorld(worldName) == null) { - Towny.getPlugin().getScheduler().runAsyncLater(() -> { - // Check if the World is still null in Bukkit and warn the admin. - if (BukkitTools.getWorld(worldName) == null) { - Towny.getPlugin().getLogger().warning("Your towny\\data\\townblocks\\ folder contains a folder named '" - + worldName + "' which doesn't appear to exist on your Bukkit server!"); - Towny.getPlugin().getLogger().warning("Towny will load the townblocks regardless, but if this world no longer exists please delete the folder."); - } - }, 20L); - } - - TownyWorld world = universe.getWorld(worldName); - if (world == null) { - newWorld(worldName); - world = universe.getWorld(worldName); - } - File worldFolder = new File(dataFolderPath + File.separator + "townblocks" + File.separator + worldName); - File[] townBlockFiles = worldFolder.listFiles(file->file.getName().endsWith(".data")); - int total = 0; - for (File townBlockFile : townBlockFiles) { - String[] coords = townBlockFile.getName().split("_"); - String[] size = coords[2].split("\\."); - // Do not load a townBlockFile if it does not use teh currently set town_block_size. - if (Integer.parseInt(size[0]) != TownySettings.getTownBlockSize()) { - mismatched = true; - mismatchedCount++; - continue; - } - int x = Integer.parseInt(coords[0]); - int z = Integer.parseInt(coords[1]); - TownBlock townBlock = new TownBlock(x, z, world); - universe.addTownBlock(townBlock); - total++; - } - TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_world_loaded_townblocks", worldName, total)); - } - if (mismatched) - TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_mismatched_townblock_size", mismatchedCount)); - - return true; - } catch (Exception e1) { - plugin.getLogger().log(Level.WARNING, "An exception occurred while loading the flatfile townblock list", e1); - return false; - } - } - - @Override - public boolean loadPlotGroupList() { - TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_loading_group_list")); - File[] plotGroupFiles = receiveObjectFiles("plotgroups", ".data"); - - if (plotGroupFiles == null) - return true; - - for (File plotGroup : plotGroupFiles) - universe.newPlotGroupInternal(UUID.fromString(plotGroup.getName().replace(".data", ""))); - - return true; - } - - @Override - public boolean loadDistrictList() { - TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_loading_district_list")); - File[] districtFiles = receiveObjectFiles("districts", ".data"); - - if (districtFiles == null) - return true; - - for (File districtFile : districtFiles) - universe.newDistrictInternal(UUID.fromString(districtFile.getName().replace(".data", ""))); - - return true; - } - - @Override - public boolean loadResidentList() { + for (File file : files) { + String fileName = file.getName(); + final NameAndId nameAndId = this.loadNameAndUUIDFromFile(file, fileName, type.name()); - TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_loading_resident_list")); - List residents = receiveListFromLegacyFile("residents.txt"); - File[] residentFiles = receiveObjectFiles("residents", ".txt"); - - for (File residentFile : residentFiles) { - String fileName = residentFile.getName().replace(".txt", ""); - - // Don't load resident files if they weren't in the residents.txt file. - if (!residents.isEmpty() && !residents.contains(fileName)) { - TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_removing_resident_not_found", residentFile.getName())); - deleteFile(residentFile.getAbsolutePath()); - continue; - } - - String name; - String uuidString; - - if (fileName.length() == UUID_LENGTH) { - name = loadKeyFromFile(residentFile, "name"); - uuidString = fileName; - } else { - uuidString = this.loadKeyFromFile(residentFile, "uuid"); - name = fileName; - } - - final @Nullable UUID uuid = super.parsePlayerUUID(uuidString, fileName); - - if (uuid == null) { - plugin.getLogger().warning("Resident '" + name + "' does not have a valid uuid and cannot be loaded."); - continue; - } - if (fileName.length() != UUID_LENGTH) { - final Path residentFilePath = residentFile.toPath(); + final Path filePath = file.toPath(); try { - Files.move(residentFilePath, residentFilePath.resolveSibling(uuid + ".txt"), StandardCopyOption.REPLACE_EXISTING); + Files.move(filePath, filePath.resolveSibling(nameAndId.uuid() + ".txt"), StandardCopyOption.REPLACE_EXISTING); } catch (IOException e) { - plugin.getSLF4JLogger().warn("Failed to rename name-based resident file '{}' to uuid variant", fileName, e); + plugin.getSLF4JLogger().warn("Failed to rename name-based file '{}' to uuid variant", fileName, e); return false; } } - - try { - newResident(name, uuid); - } catch (NotRegisteredException e) { - // Thrown if the resident name does not pass the filters. - plugin.getLogger().log(Level.WARNING, "Resident " + name + " has an invalid name", e); - return false; - } catch (AlreadyRegisteredException e) { - final Resident otherResident = universe.getResident(uuid); - if (otherResident != null && !otherResident.getName().equals(name)) { - // UUID is already registered - super.pendingDuplicateResidents.add(Pair.pair(name, otherResident.getName())); - } - } - } - - if (!residents.isEmpty()) - deleteFile(dataFolderPath + File.separator + "residents.txt"); - - return true; - - } - - @Override - public boolean loadTownList() { - - TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_loading_town_list")); - List towns = receiveListFromLegacyFile("towns.txt"); - File[] townFiles = receiveObjectFiles("towns", ".txt"); - - List rejectedTowns = new ArrayList<>(); - - for (File townFile : townFiles) { - String fileName = townFile.getName().replace(".txt", ""); - - // Don't load town files if they weren't in the towns.txt file. - if (!towns.isEmpty() && !towns.contains(fileName)) { - TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_removing_town_not_found", townFile.getName())); - deleteFile(townFile.getAbsolutePath()); - continue; - } - - final NameAndId nameAndId = this.loadNameAndUUIDFromFile(townFile, fileName, "town"); - - if (fileName.length() != UUID_LENGTH) { - final Path townFilePath = townFile.toPath(); - try { - Files.move(townFilePath, townFilePath.resolveSibling(nameAndId.uuid() + ".txt"), StandardCopyOption.REPLACE_EXISTING); - } catch (IOException e) { - plugin.getSLF4JLogger().warn("Failed to rename name-based town file '{}' to uuid variant", fileName, e); - return false; - } - } - - try { - universe.newTownInternal(nameAndId.name(), nameAndId.uuid()); - } catch (AlreadyRegisteredException | InvalidNameException e) { - // Thrown if the town name does not pass the filters. - rejectedTowns.add(nameAndId); - } - } - - // Delete legacy file towns.txt if it was present. - if (!towns.isEmpty()) - deleteFile(dataFolderPath + File.separator + "towns.txt"); - - // Handle rejected town names after all the rest are loaded. - for (NameAndId town : rejectedTowns) { - String name = town.name(); - String newName = generateReplacementName(true); - universe.getReplacementNameMap().put(name, newName); - TownyMessaging.sendErrorMsg(String.format("The town %s (%s) tried to load an invalid name, attempting to rename it to %s.", name, town.uuid(), newName)); try { - universe.newTownInternal(newName, town.uuid()); - } catch (AlreadyRegisteredException | InvalidNameException e1) { - // We really hope this doesn't fail again. - plugin.getSLF4JLogger().warn("exception occurred while registering town '{}' ({}) internally", newName, town.uuid(), e1); - return false; + // Send our NameAndId to the consumer. + consumer.accept(nameAndId); + } catch (IllegalArgumentException ignored) { + plugin.getLogger().warning("The file: " + file.getName() + " in the " + type.folderName + " folder could not be read!"); +// plugin.getLogger().warning("If your database did not convert to UUIDs in full you may open your database.yml and set the version back to 1 in order to try again."); } } - return true; - } - @Override - public boolean loadNationList() { - - TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_loading_nation_list")); - List nations = receiveListFromLegacyFile("nations.txt"); - File[] nationFiles = receiveObjectFiles("nations", ".txt"); - - List rejectedNations = new ArrayList<>(); - - for (File nationFile : nationFiles) { - String fileName = nationFile.getName().replace(".txt", ""); - - // Don't load nation files if they weren't in the nations.txt file. - if (!nations.isEmpty() && !nations.contains(fileName)) { - TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_removing_nation_not_found", nationFile.getName())); - deleteFile(nationFile.getAbsolutePath()); - continue; - } - - final NameAndId nameAndId = this.loadNameAndUUIDFromFile(nationFile, fileName, "nation"); - - if (fileName.length() != UUID_LENGTH) { - final Path nationFilePath = nationFile.toPath(); - - try { - Files.move(nationFilePath, nationFilePath.resolveSibling(nameAndId.uuid() + ".txt"), StandardCopyOption.REPLACE_EXISTING); - } catch (IOException e) { - plugin.getSLF4JLogger().warn("Failed to rename name-based nation file '{}' to uuid variant", fileName, e); - return false; - } - } - - try { - newNation(nameAndId.name(), nameAndId.uuid()); - } catch (AlreadyRegisteredException | NotRegisteredException e) { - // Thrown if the town name does not pass the filters. - rejectedNations.add(nameAndId); - } - } - - // Delete legacy file towns.txt if it was present. - if (!nations.isEmpty()) - deleteFile(dataFolderPath + File.separator + "nations.txt"); - - // Handle rejected nation names after all the rest are loaded. - for (NameAndId nation : rejectedNations) { - String name = nation.name(); - String newName = generateReplacementName(false); - universe.getReplacementNameMap().put(name, newName); - TownyMessaging.sendErrorMsg(String.format("The nation %s (%s) tried to load an invalid name, attempting to rename it to %s.", name, nation.uuid(), newName)); - try { - newNation(newName, nation.uuid()); - } catch (AlreadyRegisteredException | NotRegisteredException e1) { - // we really hope this doesn't fail a second time. - plugin.getLogger().log(Level.WARNING, "exception occurred while registering nation '" + newName + "' internally", e1); - return false; - } - } + private boolean loadFlatFilesOfType(TownyDBFileType type, Set uuids) throws ObjectCouldNotBeLoadedException { + for (UUID uuid : uuids) + if (!loadFile(type, uuid)) + throw new ObjectCouldNotBeLoadedException(type.getLoadErrorMsg(uuid)); return true; - } - - @Override - public boolean loadWorldList() { - - TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_loading_server_world_list")); - for (World world : Bukkit.getServer().getWorlds()) - universe.registerTownyWorld(new TownyWorld(world.getName(), world.getUID())); - TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_loading_world_list")); - - for (File worldFile : receiveObjectFiles("worlds", ".txt")) { - final String name = worldFile.getName().replace(".txt", ""); - - // World is already loaded by the newWorld above - if (universe.getWorld(name) != null) - continue; - - // Attempt to get the uuid from the world file - UUID uuid = null; - try { - uuid = UUID.fromString(Optional.ofNullable(this.loadKeyFromFile(worldFile, "uuid")).orElse("")); - } catch (IllegalArgumentException ignored) {} - - if (uuid != null) { - universe.registerTownyWorld(new TownyWorld(name, uuid)); - } else { - try { - newWorld(name); - } catch (AlreadyRegisteredException ignored) {} - } - } - - return true; + private boolean loadFile(TownyDBFileType type, UUID uuid) { + return switch (type) { + case JAIL -> loadJailData(uuid); + case PLOTGROUP -> loadPlotGroupData(uuid); + case RESIDENT -> loadResidentData(uuid); + case TOWN -> loadTownData(uuid); + case NATION -> loadNationData(uuid); + case WORLD -> loadWorldData(uuid); + case TOWNBLOCK -> throw new UnsupportedOperationException("Unimplemented case: " + type); + default -> throw new IllegalArgumentException("Unexpected value: " + type); + }; } - public boolean loadJailList() { - TownyMessaging.sendDebugMsg("Loading Jail List"); - File[] jailFiles = receiveObjectFiles("jails", ".txt"); - if (jailFiles == null) - return true; - - for (File jail : jailFiles) { - String uuid = jail.getName().replace(".txt", ""); - universe.newJailInternal(uuid); - } - - return true; - } - - /** - * Util method to procur a list of Towny Objects that will no longer be saved. - * ex: residents.txt, towns.txt, nations.txt, etc. - * - * @param listFile - string representing residents.txt/towns.txt/nations.txt. - * @return list - List of names of towny objects which used to be saved to the database. - */ - private List receiveListFromLegacyFile(String listFile) { - String line; - List list = new ArrayList<>(); - // Build up a list of objects from any existing legacy objects.txt files. - try (BufferedReader fin = new BufferedReader(new InputStreamReader(new FileInputStream(dataFolderPath + File.separator + listFile), StandardCharsets.UTF_8))) { - - while ((line = fin.readLine()) != null && !line.equals("")) - list.add(line); - } catch (Exception ignored) { - // No towns/residents/nations.txt any more. - } - return list; - } + private String getTownBlockFilename(TownBlock townBlock) { - /** - * Util method for gathering towny object .txt files from their parent folder. - * ex: "residents" - * @param folder - Towny object folder - * @param extension - Extension of the filetype to receive objects from. - * @return files - Files from inside the residents\towns\nations folder. - */ - private File[] receiveObjectFiles(String folder, String extension) { - return new File(dataFolderPath + File.separator + folder).listFiles(file -> file.getName().toLowerCase(Locale.ROOT).endsWith(extension)); + return dataFolderPath + File.separator + "townblocks" + File.separator + townBlock.getWorld().getUUID() + + File.separator + townBlock.getX() + "_" + townBlock.getZ() + "_" + TownySettings.getTownBlockSize() + + ".data"; } - + /* - * Load individual towny objects + * Load keys */ - + @Override - public boolean loadResident(Resident resident) { - boolean save = true; - String line = null; - String path = getResidentFilename(resident); - File fileResident = new File(path); - if (fileResident.exists() && fileResident.isFile()) { - TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_loading_resident", resident.getName())); - try { - HashMap keys = FileMgmt.loadFileIntoHashMap(fileResident); - - line = keys.get("lastOnline"); - if (line != null) - resident.setLastOnline(Long.parseLong(line)); - - line = keys.get("about"); - if (line != null) - resident.setAbout(line); - - line = keys.get("registered"); - if (line != null) - resident.setRegistered(Long.parseLong(line)); - else - resident.setRegistered(resident.getLastOnline()); - - line = keys.get("isNPC"); - if (line != null) - resident.setNPC(Boolean.parseBoolean(line)); - - line = keys.get("jail"); - if (line != null && universe.hasJail(UUID.fromString(line))) - resident.setJail(universe.getJail(UUID.fromString(line))); - - if (resident.isJailed()) { - line = keys.get("jailCell"); - if (line != null) - resident.setJailCell(Integer.parseInt(line)); - - line = keys.get("jailHours"); - if (line != null) - resident.setJailHours(Integer.parseInt(line)); - - line = keys.get("jailBail"); - if (line != null) - resident.setJailBailCost(Double.parseDouble(line)); - } - - line = keys.get("friends"); - if (line != null) { - final String[] split = line.split(","); - final UUID[] friendUUIDs = toUUIDArray(split); - - List friends = friendUUIDs.length > 0 ? api.getResidents(friendUUIDs) : api.getResidents(split); - for (Resident friend : friends) { - resident.addFriend(friend); - } - } - - line = keys.get("protectionStatus"); - if (line != null) - resident.setPermissions(line); - - line = keys.get("metadata"); - if (line != null && !line.isEmpty()) - MetadataLoader.getInstance().deserializeMetadata(resident, line.trim()); - - line = keys.get("town"); - if (line != null) { - Town town = null; - - final UUID townUUID = JavaUtil.parseUUIDOrNull(line); - - if (townUUID != null && universe.hasTown(townUUID)) { - town = universe.getTown(townUUID); - } else if (universe.hasTown(line)) { - town = universe.getTown(line); - } else if (universe.getReplacementNameMap().containsKey(line)) { - town = universe.getTown(universe.getReplacementNameMap().get(line)); - } else { - TownyMessaging.sendErrorMsg(Translation.of("flatfile_err_resident_tried_load_invalid_town", resident.getName(), line)); - } - - if (town != null) { - resident.setTown(town, false); - - line = keys.get("title"); - if (line != null) - resident.setTitle(line); - - line = keys.get("surname"); - if (line != null) - resident.setSurname(line); - - try { - line = keys.get("town-ranks"); - if (line != null) - resident.setTownRanks(Arrays.asList((line.split(",")))); - } catch (Exception ignored) {} - - try { - line = keys.get("nation-ranks"); - if (line != null) - resident.setNationRanks(Arrays.asList((line.split(",")))); - } catch (Exception ignored) {} - - line = keys.get("joinedTownAt"); - if (line != null) { - resident.setJoinedTownAt(Long.parseLong(line)); - } - } - } - } catch (Exception e) { - plugin.getLogger().log(Level.WARNING, Translation.of("flatfile_err_reading_resident_at_line", resident.getName(), line, resident.getName()), e); - return false; - } finally { - if (save) saveResident(resident); - } - return true; - } else { - return false; - } - + public boolean loadJailList() { + return loadFlatFileListOfType(TownyDBFileType.JAIL, nameAndId -> universe.newJailInternal(nameAndId.uuid())); } - - @Override - public boolean loadTown(Town town) { - String line = null; - String[] tokens; - String path = getTownFilename(town); - File fileTown = new File(path); - if (fileTown.exists() && fileTown.isFile()) { - TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_loading_town", town.getName())); - try { - HashMap keys = FileMgmt.loadFileIntoHashMap(fileTown); - - line = keys.get("mayor"); - if (line != null) { - try { - final UUID mayorUUID = JavaUtil.parseUUIDOrNull(line); - Resident res = mayorUUID != null ? universe.getResident(mayorUUID) : universe.getResident(line); - if (res == null) - throw new TownyException(); - - town.forceSetMayor(res); - } catch (TownyException e1) { - if (town.getResidents().isEmpty()) - removeTown(town, DeleteTownEvent.Cause.LOAD, null, false); - else - town.findNewMayor(); - - return true; - } - } - - line = keys.get("outlaws"); - if (line != null) { - tokens = line.split(","); - final UUID[] outlawUUIDs = toUUIDArray(tokens); - final List outlaws = outlawUUIDs.length > 0 ? api.getResidents(outlawUUIDs) : api.getResidents(tokens); - - for (Resident outlaw : outlaws) { - TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_town_fetch_outlaw", outlaw.getName())); - - try { - town.addOutlaw(outlaw); - } catch (AlreadyRegisteredException ex) { - TownyMessaging.sendErrorMsg(Translation.of("flatfile_err_reading_outlaw_of_town_duplicate", town.getName(), outlaw.getName())); - } - } - } - - line = keys.get("townBoard"); - if (line != null) - town.setBoard(line); - - line = keys.get("founder"); - if (line != null) - town.setFounder(line); - - line = keys.get("tag"); - if (line != null) - town.setTag(line); - - line = keys.get("protectionStatus"); - if (line != null) - town.setPermissions(line); - - line = keys.get("bonusBlocks"); - if (line != null) - try { - town.setBonusBlocks(Integer.parseInt(line)); - } catch (Exception e) { - town.setBonusBlocks(0); - } - - line = keys.get("purchasedBlocks"); - if (line != null) - try { - town.setPurchasedBlocks(Integer.parseInt(line)); - } catch (Exception e) { - town.setPurchasedBlocks(0); - } - - line = keys.get("plotPrice"); - if (line != null) - try { - town.setPlotPrice(Double.parseDouble(line)); - } catch (Exception e) { - town.setPlotPrice(0); - } - - line = keys.get("hasUpkeep"); - if (line != null) - try { - town.setHasUpkeep(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("hasUnlimitedClaims"); - if (line != null) - try { - town.setHasUnlimitedClaims(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("visibleOnTopLists"); - if (line != null) - try { - town.setVisibleOnTopLists(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - line = keys.get("taxpercent"); - if (line != null) - try { - town.setTaxPercentage(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("maxPercentTaxAmount"); - if (line != null) - town.setMaxPercentTaxAmount(Double.parseDouble(line)); - else - town.setMaxPercentTaxAmount(TownySettings.getMaxTownTaxPercentAmount()); - - line = keys.get("taxes"); - if (line != null) - try { - town.setTaxes(Double.parseDouble(line)); - } catch (Exception e) { - town.setTaxes(0); - } - - line = keys.get("plotTax"); - if (line != null) - try { - town.setPlotTax(Double.parseDouble(line)); - } catch (Exception e) { - town.setPlotTax(0); - } - - line = keys.get("commercialPlotPrice"); - if (line != null) - try { - town.setCommercialPlotPrice(Double.parseDouble(line)); - } catch (Exception e) { - town.setCommercialPlotPrice(0); - } - - line = keys.get("commercialPlotTax"); - if (line != null) - try { - town.setCommercialPlotTax(Double.parseDouble(line)); - } catch (Exception e) { - town.setCommercialPlotTax(0); - } - - line = keys.get("embassyPlotPrice"); - if (line != null) - try { - town.setEmbassyPlotPrice(Double.parseDouble(line)); - } catch (Exception e) { - town.setEmbassyPlotPrice(0); - } - - line = keys.get("embassyPlotTax"); - if (line != null) - try { - town.setEmbassyPlotTax(Double.parseDouble(line)); - } catch (Exception e) { - town.setEmbassyPlotTax(0); - } - - line = keys.get("spawnCost"); - if (line != null) - try { - town.setSpawnCost(Double.parseDouble(line)); - } catch (Exception e) { - town.setSpawnCost(TownySettings.getSpawnTravelCost()); - } - - line = keys.get("adminDisabledPvP"); - if (line != null) - try { - town.setAdminDisabledPVP(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("adminEnabledPvP"); - if (line != null) - try { - town.setAdminEnabledPVP(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("adminEnabledMobs"); - if (line != null) - try { - town.setAdminEnabledMobs(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("allowedToWar"); - if (line != null) - try { - town.setAllowedToWar(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("open"); - if (line != null) - try { - town.setOpen(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - line = keys.get("public"); - if (line != null) - try { - town.setPublic(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - line = keys.get("forSale"); - if (line != null) - try { - town.setForSale(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - line = keys.get("forSalePrice"); - if (line != null) - try { - town.setForSalePrice(Double.parseDouble(line)); - } catch (Exception ignored) { - } - line = keys.get("forSaleTime"); - if (line != null) - try { - town.setForSaleTime(Long.parseLong(line)); - } catch (Exception ee) { - town.setForSaleTime(0); - } - line = keys.get("conquered"); - if (line != null) - try { - town.setConquered(Boolean.parseBoolean(line), false); - } catch (Exception ignored) { - } - line = keys.get("conqueredDays"); - if (line != null) - town.setConqueredDays(Integer.parseInt(line)); - - line = keys.get("joinedNationAt"); - if (line != null) - try { - town.setJoinedNationAt(Long.parseLong(line)); - } catch (Exception ignored) {} - - line = keys.get("movedHomeBlockAt"); - if (line != null) - try { - town.setMovedHomeBlockAt(Long.parseLong(line)); - } catch (Exception ignored) {} - - line = keys.get("homeBlock"); - if (line != null) { - tokens = line.split(","); - if (tokens.length == 3) { - TownyWorld world = universe.getWorld(tokens[0]); - if (world == null) - TownyMessaging.sendErrorMsg(Translation.of("flatfile_err_homeblock_load_invalid_world", town.getName())); - else { - try { - int x = Integer.parseInt(tokens[1]); - int z = Integer.parseInt(tokens[2]); - TownBlock homeBlock = universe.getTownBlock(new WorldCoord(world.getName(), x, z)); - town.forceSetHomeBlock(homeBlock); - } catch (NumberFormatException e) { - TownyMessaging.sendErrorMsg(Translation.of("flatfile_err_homeblock_load_invalid_location", town.getName())); - } catch (NotRegisteredException e) { - TownyMessaging.sendErrorMsg(Translation.of("flatfile_err_homeblock_load_invalid_townblock", town.getName())); - } catch (TownyException e) { - TownyMessaging.sendErrorMsg(Translation.of("flatfile_err_town_homeblock_not_exist", town.getName())); - } - } - } - } - - line = keys.get("spawn"); - if (line != null) { - tokens = line.split(","); - if (tokens.length >= 4) - try { - town.spawnPosition(Position.deserialize(tokens)); - } catch (IllegalArgumentException e) { - plugin.getLogger().warning("Failed to load spawn location for town " + town.getName() + ": " + e.getMessage()); - } - } - - // Load outpost spawns - line = keys.get("outpostspawns"); - if (line != null) { - String[] outposts = line.split(";"); - for (String spawn : outposts) { - tokens = spawn.split(","); - if (tokens.length >= 4) - try { - town.forceAddOutpostSpawn(Position.deserialize(tokens)); - } catch (IllegalArgumentException e) { - plugin.getLogger().warning("Failed to load an outpost spawn location for town " + town.getName() + ": " + e.getMessage()); - } - } - } - - // Load legacy jail spawns into new Jail objects. - line = keys.get("jailspawns"); - if (line != null) { - String[] jails = line.split(";"); - for (String spawn : jails) { - tokens = spawn.split(","); - if (tokens.length >= 4) - try { - final Position position = Position.deserialize(tokens); - TownBlock tb = universe.getTownBlockOrNull(position.worldCoord()); - if (tb == null) - continue; - - Jail jail = new Jail(UUID.randomUUID(), town, tb, Collections.singleton(position)); - universe.registerJail(jail); - town.addJail(jail); - tb.setJail(jail); - jail.save(); - } catch (IllegalArgumentException e) { - plugin.getLogger().warning("Failed to load a legacy jail spawn location for town " + town.getName() + ": " + e.getMessage()); - } - } - } - - line = keys.get("registered"); - if (line != null) { - try { - town.setRegistered(Long.parseLong(line)); - } catch (Exception ee) { - town.setRegistered(0); - } - } - - line = keys.get("metadata"); - if (line != null && !line.isEmpty()) - MetadataLoader.getInstance().deserializeMetadata(town, line.trim()); - - line = keys.get("manualTownLevel"); - if (line != null) - town.setManualTownLevel(Integer.parseInt(line)); - - line = keys.get("nation"); - if (line != null && !line.isEmpty()) { - line = line.trim(); - final UUID nationUUID = JavaUtil.parseUUIDOrNull(line); - - Nation nation = null; - if (nationUUID != null && universe.hasNation(nationUUID)) { - nation = universe.getNation(nationUUID); - } else if (universe.hasNation(line)) - nation = universe.getNation(line); - else if (universe.getReplacementNameMap().containsKey(line)) - nation = universe.getNation(universe.getReplacementNameMap().get(line)); - - // Only set the nation if it exists - if (nation != null) - town.setNation(nation, false); - } - - line = keys.get("ruined"); - if (line != null) - try { - town.setRuined(Boolean.parseBoolean(line)); - } catch (Exception e) { - town.setRuined(false); - } - - line = keys.get("ruinedTime"); - if (line != null) - try { - town.setRuinedTime(Long.parseLong(line)); - } catch (Exception ee) { - town.setRuinedTime(0); - } - - line = keys.get("neutral"); - if (line != null) - town.setNeutral(Boolean.parseBoolean(line)); - - line = keys.get("debtBalance"); - if (line != null) - try { - town.setDebtBalance(Double.parseDouble(line)); - } catch (Exception e) { - town.setDebtBalance(0.0); - } - - line = keys.get("primaryJail"); - if (line != null) { - UUID uuid = UUID.fromString(line); - if (universe.hasJail(uuid)) - town.setPrimaryJail(universe.getJail(uuid)); - } - - line = keys.get("trustedResidents"); - if (line != null && !line.isEmpty()) { - for (Resident resident : TownyAPI.getInstance().getResidents(toUUIDArray(line.split(",")))) - town.addTrustedResident(resident); - } - - line = keys.get("trustedTowns"); - if (line != null && !line.isEmpty()) { - List uuids = Arrays.stream(line.split(",")) - .map(UUID::fromString) - .collect(Collectors.toList()); - town.loadTrustedTowns(TownyAPI.getInstance().getTowns(uuids)); - } - - line = keys.get("mapColorHexCode"); - if (line != null) { - try { - town.setMapColorHexCode(line); - } catch (Exception e) { - town.setMapColorHexCode(MapUtil.generateRandomTownColourAsHexCode()); - } - } else { - town.setMapColorHexCode(MapUtil.generateRandomTownColourAsHexCode()); - } - - line = keys.get("nationZoneOverride"); - if (line != null) - try { - town.setNationZoneOverride(Integer.parseInt(line)); - } catch (Exception ignored) { - } - - line = keys.get("nationZoneEnabled"); - if (line != null) - town.setNationZoneEnabled(Boolean.parseBoolean(line)); - - line = keys.get("allies"); - if (line != null && !line.isEmpty()) { - List uuids = Arrays.stream(line.split(",")) - .map(uuid -> UUID.fromString(uuid)) - .collect(Collectors.toList()); - town.loadAllies(TownyAPI.getInstance().getTowns(uuids)); - } - - line = keys.get("enemies"); - if (line != null && !line.isEmpty()) { - List uuids = Arrays.stream(line.split(",")) - .map(uuid -> UUID.fromString(uuid)) - .collect(Collectors.toList()); - town.loadEnemies(TownyAPI.getInstance().getTowns(uuids)); - } - - line = keys.get("hasActiveWar"); - if (line != null) - town.setActiveWar(Boolean.parseBoolean(line)); - - } catch (Exception e) { - plugin.getLogger().log(Level.WARNING, Translation.of("flatfile_err_reading_town_file_at_line", town.getName(), line, town.getName()), e); - return false; - } finally { - if (town.exists()) - saveTown(town); - } - return true; - } else { - return false; - } - } - @Override - public boolean loadNation(Nation nation) { - - String line = ""; - String[] tokens; - String path = getNationFilename(nation); - File fileNation = new File(path); - boolean save = false; - - if (fileNation.exists() && fileNation.isFile()) { - TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_loading_nation", nation.getName())); - try { - HashMap keys = FileMgmt.loadFileIntoHashMap(fileNation); - - line = keys.get("capital"); - String cantLoadCapital = Translation.of("flatfile_err_nation_could_not_load_capital_disband", nation.getName()); - if (line != null) { - final UUID capitalUUID = JavaUtil.parseUUIDOrNull(line); - - Town town = capitalUUID != null ? universe.getTown(capitalUUID) : universe.getTown(line); - if (town != null) { - try { - nation.forceSetCapital(town); - } catch (EmptyNationException e1) { - plugin.getLogger().warning(cantLoadCapital); - removeNation(nation, DeleteNationEvent.Cause.LOAD); - return true; - } - } - else { - TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_cannot_set_capital_try_next", nation.getName(), line)); - if (!nation.findNewCapital()) { - plugin.getLogger().warning(cantLoadCapital); - removeNation(nation, DeleteNationEvent.Cause.LOAD); - return true; - } - } - } else { - TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_undefined_capital_select_new", nation.getName())); - if (!nation.findNewCapital()) { - plugin.getLogger().warning(cantLoadCapital); - removeNation(nation, DeleteNationEvent.Cause.LOAD); - return true; - } - } - - save = true; - line = keys.get("nationBoard"); - if (line != null) - try { - nation.setBoard(line); - } catch (Exception e) { - nation.setBoard(""); - } - - line = keys.get("mapColorHexCode"); - if (line != null) { - try { - nation.setMapColorHexCode(line); - } catch (Exception e) { - nation.setMapColorHexCode(MapUtil.generateRandomNationColourAsHexCode()); - } - } else { - nation.setMapColorHexCode(MapUtil.generateRandomNationColourAsHexCode()); - } - - line = keys.get("tag"); - if (line != null) - nation.setTag(line); - - line = keys.get("allies"); - if (line != null) { - final String[] split = line.split(","); - final UUID[] allyUUIDs = toUUIDArray(split); - - List allies = allyUUIDs.length > 0 ? api.getNations(allyUUIDs) : api.getNations(split); - for (Nation ally : allies) { - nation.addAlly(ally); - } - } - - line = keys.get("enemies"); - if (line != null) { - final String[] split = line.split(","); - final UUID[] enemyUUIDs = toUUIDArray(split); - - List enemies = enemyUUIDs.length > 0 ? api.getNations(enemyUUIDs) : api.getNations(split); - for (Nation enemy : enemies) { - nation.addEnemy(enemy); - } - } - - line = keys.get("spawnCost"); - if (line != null) - try { - nation.setSpawnCost(Double.parseDouble(line)); - } catch (Exception e) { - nation.setSpawnCost(TownySettings.getSpawnTravelCost()); - } - - line = keys.get("neutral"); - if (line != null) - nation.setNeutral(Boolean.parseBoolean(line)); - - line = keys.get("registered"); - if (line != null) { - try { - nation.setRegistered(Long.parseLong(line)); - } catch (Exception ee) { - nation.setRegistered(0); - } - } - - line = keys.get("nationSpawn"); - if (line != null) { - tokens = line.split(","); - if (tokens.length >= 4) - try { - nation.spawnPosition(Position.deserialize(tokens)); - } catch (IllegalArgumentException e) { - plugin.getLogger().warning("Failed to load nation spawn location for nation " + nation.getName() + ": " + e.getMessage()); - } - } - - line = keys.get("isPublic"); - if (line != null) - try { - nation.setPublic(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - line = keys.get("isOpen"); - if (line != null) - try { - nation.setOpen(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("taxpercent"); - if (line != null) - try { - nation.setTaxPercentage(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("maxPercentTaxAmount"); - if (line != null) - nation.setMaxPercentTaxAmount(Double.parseDouble(line)); - else - nation.setMaxPercentTaxAmount(TownySettings.getMaxNationTaxPercentAmount()); - - line = keys.get("taxes"); - if (line != null) - try { - nation.setTaxes(Double.parseDouble(line)); - } catch (Exception e) { - nation.setTaxes(0.0); - } - - line = keys.get("metadata"); - if (line != null && !line.isEmpty()) - MetadataLoader.getInstance().deserializeMetadata(nation, line.trim()); - - line = keys.get("conqueredTax"); - if (line != null && !line.isEmpty()) - nation.setConqueredTax(Double.parseDouble(line)); - - line = keys.get("sanctionedTowns"); - if (line != null) { - nation.loadSanctionedTowns(line.split("#")); - } - - line = keys.get("hasActiveWar"); - if (line != null) - nation.setActiveWar(Boolean.parseBoolean(line)); - - line = keys.get("manualNationLevel"); - if (line != null) - nation.setManualNationLevel(Integer.parseInt(line)); - - } catch (Exception e) { - plugin.getLogger().log(Level.WARNING, Translation.of("flatfile_err_reading_nation_file_at_line", nation.getName(), line, nation.getName()), e); - return false; - } finally { - if (save) - saveNation(nation); - } - return true; - } else { - return false; - } + public boolean loadPlotGroupList() { + return loadFlatFileListOfType(TownyDBFileType.PLOTGROUP, nameAndId -> universe.newPlotGroupInternal(nameAndId.uuid())); } - - @Override - public boolean loadWorld(TownyWorld world) { - - String line = ""; - String path = getWorldFilename(world); - - // create the world file if it doesn't exist - if (!FileMgmt.checkOrCreateFile(path)) { - TownyMessaging.sendErrorMsg(Translation.of("flatfile_err_exception_reading_file", path)); - } - - File fileWorld = new File(path); - if (fileWorld.exists() && fileWorld.isFile()) { - TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_loading_world", world.getName())); - try { - HashMap keys = FileMgmt.loadFileIntoHashMap(fileWorld); - - line = keys.get("claimable"); - if (line != null) - try { - world.setClaimable(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("pvp"); - if (line != null) - try { - world.setPVP(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("forcepvp"); - if (line != null) - try { - world.setForcePVP(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("friendlyFire"); - if (line != null) - try { - world.setFriendlyFire(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("forcetownmobs"); - if (line != null) - try { - world.setForceTownMobs(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - line = keys.get("wildernessmobs"); - if (line != null) - try { - world.setWildernessMobs(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("worldmobs"); - if (line != null) - try { - world.setWorldMobs(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("firespread"); - if (line != null) - try { - world.setFire(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("forcefirespread"); - if (line != null) - try { - world.setForceFire(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("explosions"); - if (line != null) - try { - world.setExpl(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("forceexplosions"); - if (line != null) - try { - world.setForceExpl(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("endermanprotect"); - if (line != null) - try { - world.setEndermanProtect(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("disablecreaturetrample"); - if (line != null) - try { - world.setDisableCreatureTrample(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("unclaimedZoneBuild"); - if (line != null) - try { - world.setUnclaimedZoneBuild(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - line = keys.get("unclaimedZoneDestroy"); - if (line != null) - try { - world.setUnclaimedZoneDestroy(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - line = keys.get("unclaimedZoneSwitch"); - if (line != null) - try { - world.setUnclaimedZoneSwitch(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - line = keys.get("unclaimedZoneItemUse"); - if (line != null) - try { - world.setUnclaimedZoneItemUse(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - line = keys.get("unclaimedZoneName"); - if (line != null) - try { - world.setUnclaimedZoneName(line); - } catch (Exception ignored) { - } - line = keys.get("unclaimedZoneIgnoreIds"); - if (line != null) - try { - List mats = new ArrayList<>(); - for (String s : line.split(",")) - if (!s.isEmpty()) - mats.add(s); - - world.setUnclaimedZoneIgnore(mats); - } catch (Exception ignored) { - } - - line = keys.get("isDeletingEntitiesOnUnclaim"); - if (line != null) - try { - world.setDeletingEntitiesOnUnclaim(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("unclaimDeleteEntityTypes"); - if (line != null) - try { - List entityTypes = new ArrayList<>(); - for (String s : line.split(",")) - if (!s.isEmpty()) - entityTypes.add(s); - - world.setUnclaimDeleteEntityTypes(entityTypes); - } catch (Exception ignored) { - } - - line = keys.get("usingPlotManagementDelete"); - if (line != null) - try { - world.setUsingPlotManagementDelete(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - line = keys.get("plotManagementDeleteIds"); - if (line != null) - try { - //List nums = new ArrayList(); - List mats = new ArrayList<>(); - for (String s : line.split(",")) - if (!s.isEmpty()) - mats.add(s); - - world.setPlotManagementDeleteIds(mats); - } catch (Exception ignored) { - } - - line = keys.get("usingPlotManagementMayorDelete"); - if (line != null) - try { - world.setUsingPlotManagementMayorDelete(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - line = keys.get("plotManagementMayorDelete"); - if (line != null) - try { - List materials = new ArrayList<>(); - for (String s : line.split(",")) - if (!s.isEmpty()) - try { - materials.add(s.toUpperCase().trim()); - } catch (NumberFormatException ignored) { - } - world.setPlotManagementMayorDelete(materials); - } catch (Exception ignored) { - } - - line = keys.get("usingPlotManagementRevert"); - if (line != null) - try { - world.setUsingPlotManagementRevert(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("plotManagementIgnoreIds"); - if (line != null) - try { - List mats = new ArrayList<>(); - for (String s : line.split(",")) - if (!s.isEmpty()) - mats.add(s); - - world.setPlotManagementIgnoreIds(mats); - } catch (Exception ignored) { - } - - line = keys.get("revertOnUnclaimWhitelistMaterials"); - if (line != null) - try { - List mats = new ArrayList<>(); - for (String s : line.split("#")) - if (!s.isEmpty()) - mats.add(s); - - world.setRevertOnUnclaimWhitelistMaterials(mats); - } catch (Exception ignored) { - } - - line = keys.get("usingPlotManagementWildRegen"); - if (line != null) - try { - world.setUsingPlotManagementWildEntityRevert(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("PlotManagementWildRegenEntities"); - if (line != null) - try { - List entities = new ArrayList<>(); - for (String s : line.split(",")) - if (!s.isEmpty()) - try { - entities.add(s.trim()); - } catch (NumberFormatException ignored) { - } - world.setPlotManagementWildRevertEntities(entities); - } catch (Exception ignored) { - } - - line = keys.get("PlotManagementWildRegenBlockWhitelist"); - if (line != null) - try { - List mats = new ArrayList<>(); - for (String s : line.split(",")) - if (!s.isEmpty()) - try { - mats.add(s.trim()); - } catch (NumberFormatException ignored) { - } - world.setPlotManagementWildRevertBlockWhitelist(mats); - } catch (Exception ignored) { - } - - line = keys.get("wildRegenBlocksToNotOverwrite"); - if (line != null) - try { - List mats = new ArrayList<>(); - for (String s : line.split(",")) - if (!s.isEmpty()) - try { - mats.add(s.trim()); - } catch (NumberFormatException ignored) { - } - world.setWildRevertMaterialsToNotOverwrite(mats); - } catch (Exception ignored) { - } - - line = keys.get("usingPlotManagementWildRegenDelay"); - if (line != null) - try { - world.setPlotManagementWildRevertDelay(Long.parseLong(line)); - } catch (Exception ignored) { - } - - line = keys.get("usingPlotManagementWildRegenBlocks"); - if (line != null) - try { - world.setUsingPlotManagementWildBlockRevert(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("PlotManagementWildRegenBlocks"); - if (line != null) - try { - List mats = new ArrayList<>(); - for (String s : line.split(",")) - if (!s.isEmpty()) - try { - mats.add(s.trim()); - } catch (NumberFormatException ignored) { - } - world.setPlotManagementWildRevertMaterials(mats); - } catch (Exception ignored) { - } - - line = keys.get("usingTowny"); - if (line != null) - try { - world.setUsingTowny(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("warAllowed"); - if (line != null) - try { - world.setWarAllowed(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("jailing"); - if (line != null) - try { - world.setJailingEnabled(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("metadata"); - if (line != null && !line.isEmpty()) - MetadataLoader.getInstance().deserializeMetadata(world, line.trim()); - - } catch (Exception e) { - TownyMessaging.sendErrorMsg(Translation.of("flatfile_err_exception_reading_world_file_at_line", path, line, world.getName())); - return false; - } finally { - saveWorld(world); - } - return true; - } else { - TownyMessaging.sendErrorMsg(Translation.of("flatfile_err_file_error_reading_world_file_at_line", world.getName(), line, world.getName())); - return false; - } + @Override + public boolean loadDistrictList() { + return loadFlatFileListOfType(TownyDBFileType.DISTRICT, nameAndId -> universe.newDistrictInternal(nameAndId.uuid())); } - - public boolean loadPlotGroup(PlotGroup group) { - String line = ""; - String path = getPlotGroupFilename(group); - File groupFile = new File(path); - if (groupFile.exists() && groupFile.isFile()) { - try { - HashMap keys = FileMgmt.loadFileIntoHashMap(groupFile); - - line = keys.get("groupName"); - if (line != null) - group.setName(line.trim()); - - line = keys.get("town"); - if (line != null && !line.isEmpty()) { - line = line.trim(); - final UUID townUUID = JavaUtil.parseUUIDOrNull(line); - - Town town = townUUID != null ? universe.getTown(townUUID) : universe.getTown(line); - if (town != null) { - group.setTown(town); - } else { - TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_group_file_missing_town_delete", path)); - deletePlotGroup(group); - TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_missing_file_delete_group_entry", path)); - return true; - } - } else { - TownyMessaging.sendErrorMsg(Translation.of("flatfile_err_could_not_add_to_town")); - deletePlotGroup(group); + @Override + public boolean loadResidentList() { + return loadFlatFileListOfType(TownyDBFileType.RESIDENT, nameAndId -> { + if (!universe.hasResident(nameAndId.uuid())) + universe.newResidentInternal(nameAndId.name(), nameAndId.uuid()); + else { + final Resident otherResident = universe.getResident(nameAndId.uuid()); + if (otherResident != null && !otherResident.getName().equals(nameAndId.name())) { + // UUID is already registered + super.pendingDuplicateResidents.add(Pair.pair(nameAndId.name(), otherResident.getName())); } - - line = keys.get("groupPrice"); - if (line != null && !line.isEmpty()) - group.setPrice(Double.parseDouble(line.trim())); - - line = keys.get("metadata"); - if (line != null) - MetadataLoader.getInstance().deserializeMetadata(group, line.trim()); - - } catch (Exception e) { - TownyMessaging.sendErrorMsg(Translation.of("flatfile_err_exception_reading_group_file_at_line", path, line)); - return false; } - } else { - TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_missing_file_delete_groups_entry", path)); - } - - return true; + }); } - public boolean loadDistrict(District district) { - String line = ""; - String path = getDistrictFilename(district); - - File districtFile = new File(path); - if (districtFile.exists() && districtFile.isFile()) { - try { - HashMap keys = FileMgmt.loadFileIntoHashMap(districtFile); - - line = keys.get("districtName"); - if (line != null) - district.setName(line.trim()); - - line = keys.get("town"); - if (line != null && !line.isEmpty()) { - UUID uuid = UUID.fromString(line.trim()); - if (uuid == null) { - TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_missing_file_delete_district_entry", path)); - deleteDistrict(district); - return true; - } - Town town = universe.getTown(uuid); - if (town != null) { - district.setTown(town); - } else { - TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_district_file_missing_town_delete", path)); - deleteDistrict(district); - TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_missing_file_delete_district_entry", path)); - return true; - } - } else { - TownyMessaging.sendErrorMsg(Translation.of("flatfile_err_could_not_add_to_town")); - deleteDistrict(district); - } - - line = keys.get("metadata"); - if (line != null) - MetadataLoader.getInstance().deserializeMetadata(district, line.trim()); - - } catch (Exception e) { - TownyMessaging.sendErrorMsg(Translation.of("flatfile_err_exception_reading_district_file_at_line", path, line)); - return false; - } - } - - return true; - } - @Override - public boolean loadTownBlocks() { - - String line = ""; - String path; - - List toSave = new ArrayList<>(); - for (TownBlock townBlock : universe.getTownBlocks().values()) { - path = getTownBlockFilename(townBlock); - - File fileTownBlock = new File(path); - if (fileTownBlock.exists() && fileTownBlock.isFile()) { - - try { - HashMap keys = FileMgmt.loadFileIntoHashMap(fileTownBlock); - - line = keys.get("town"); - if (line != null) { - line = line.trim(); - - if (line.isEmpty()) { - TownyMessaging.sendErrorMsg(Translation.of("flatfile_err_townblock_file_missing_town_delete", path)); - universe.removeTownBlock(townBlock); - deleteTownBlock(townBlock); - continue; - } - - final UUID townUUID = JavaUtil.parseUUIDOrNull(line); - - Town town = null; - if (townUUID != null && universe.hasTown(townUUID)) { - town = universe.getTown(townUUID); - } else if (universe.hasTown(line)) - town = universe.getTown(line); - else if (universe.getReplacementNameMap().containsKey(line)) { - town = universe.getTown(universe.getReplacementNameMap().get(line)); - toSave.add(townBlock); - } - - if (town == null) { - TownyMessaging.sendErrorMsg(Translation.of("flatfile_err_townblock_file_contains_unregistered_town_delete", line, path)); - universe.removeTownBlock(townBlock); - deleteTownBlock(townBlock); - continue; - } - - townBlock.setTown(town, false); - try { - town.addTownBlock(townBlock); - TownyWorld townyWorld = townBlock.getWorld(); - if (townyWorld != null && !townyWorld.hasTown(town)) - townyWorld.addTown(town); - } catch (AlreadyRegisteredException ignored) { - } - } else { - // Town line is null, townblock is invalid. - TownyMessaging.sendErrorMsg(Translation.of("flatfile_err_townblock_file_missing_town_delete", path)); - universe.removeTownBlock(townBlock); - deleteTownBlock(townBlock); - continue; - } - - line = keys.get("name"); - if (line != null) - try { - townBlock.setName(line.trim()); - } catch (Exception ignored) { - } - - line = keys.get("resident"); - if (line != null && !line.isEmpty()) { - line = line.trim(); - - final UUID residentUUID = JavaUtil.parseUUIDOrNull(line); - Resident res = residentUUID != null ? universe.getResident(residentUUID) : universe.getResident(line); - if (res != null) { - townBlock.setResident(res, false); - } - else { - TownyMessaging.sendErrorMsg(Translation.of("flatfile_err_invalid_townblock_resident", townBlock.toString())); - } - } - - line = keys.get("type"); - if (line != null) - townBlock.setType(TownBlockTypeHandler.getTypeInternal(line)); - - line = keys.get("price"); - if (line != null) - try { - townBlock.setPlotPrice(Double.parseDouble(line.trim())); - } catch (Exception ignored) { - } - - line = keys.get("taxed"); - if (line != null) - try { - townBlock.setTaxed(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("outpost"); - if (line != null) - try { - townBlock.setOutpost(Boolean.parseBoolean(line)); - } catch (Exception ignored) { - } - - line = keys.get("permissions"); - if ((line != null) && !line.isEmpty()) - try { - townBlock.setPermissions(line.trim()); - } catch (Exception ignored) { - } - - line = keys.get("changed"); - if (line != null) - try { - townBlock.setChanged(Boolean.parseBoolean(line.trim())); - } catch (Exception ignored) { - } - - line = keys.get("claimedAt"); - if (line != null) - try { - townBlock.setClaimedAt(Long.parseLong(line)); - } catch (Exception ignored) {} - - line = keys.get("minTownMembershipDays"); - if (line != null && !line.isEmpty()) - townBlock.setMinTownMembershipDays(Integer.valueOf(line)); - - line = keys.get("maxTownMembershipDays"); - if (line != null && !line.isEmpty()) - townBlock.setMaxTownMembershipDays(Integer.valueOf(line)); - - line = keys.get("metadata"); - if (line != null && !line.isEmpty()) - MetadataLoader.getInstance().deserializeMetadata(townBlock, line.trim()); - - line = keys.get("groupID"); - UUID groupID = null; - if (line != null && !line.isEmpty()) { - groupID = UUID.fromString(line.trim()); - } - - if (groupID != null) { - PlotGroup group = universe.getGroup(groupID); - if (group != null) { - townBlock.setPlotObjectGroup(group); - if (group.getPermissions() == null && townBlock.getPermissions() != null) - group.setPermissions(townBlock.getPermissions()); - if (townBlock.hasResident()) - group.setResident(townBlock.getResidentOrNull()); - } else { - townBlock.removePlotObjectGroup(); - } - } + public boolean loadTownList() { + return loadFlatFileListOfType(TownyDBFileType.TOWN, nameAndId -> universe.newTownInternal(nameAndId.name(), nameAndId.uuid())); + } - line = keys.get("districtID"); - UUID districtID = null; - if (line != null && !line.isEmpty()) { - districtID = UUID.fromString(line.trim()); - } - - if (districtID != null) { - District district = universe.getDistrict(districtID); - if (district != null) { - townBlock.setDistrict(district); - } else { - townBlock.removeDistrict(); - } - } + @Override + public boolean loadNationList() { + return loadFlatFileListOfType(TownyDBFileType.NATION, nameAndId -> universe.newNationInternal(nameAndId.name(), nameAndId.uuid())); + } - line = keys.get("trustedResidents"); - if (line != null && !line.isEmpty()) { - for (Resident resident : TownyAPI.getInstance().getResidents(toUUIDArray(line.split(",")))) - townBlock.addTrustedResident(resident); - - if (townBlock.hasPlotObjectGroup() && townBlock.getPlotObjectGroup().getTrustedResidents().isEmpty() && townBlock.hasTrustedResidents()) { - townBlock.getPlotObjectGroup().setTrustedResidents(townBlock.getTrustedResidents()); - } - } - - line = keys.get("customPermissionData"); - if (line != null && !line.isEmpty()) { - Map map = new Gson().fromJson(line, new TypeToken>(){}.getType()); - - for (Map.Entry entry : map.entrySet()) { - Resident resident; - try { - resident = TownyAPI.getInstance().getResident(UUID.fromString(entry.getKey())); - } catch (IllegalArgumentException e) { - continue; - } - - if (resident == null) - continue; - - townBlock.getPermissionOverrides().put(resident, new PermissionData(entry.getValue())); - } - - if (townBlock.hasPlotObjectGroup() && townBlock.getPlotObjectGroup().getPermissionOverrides().isEmpty() && townBlock.hasPermissionOverrides()) { - townBlock.getPlotObjectGroup().setPermissionOverrides(townBlock.getPermissionOverrides()); - } - } + @Override + public boolean loadWorldList() { + TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_loading_server_world_list")); + loadFlatFileListOfType(TownyDBFileType.WORLD, nameAndId -> universe.newWorldInternal(nameAndId.name(), nameAndId.uuid())); + for (World world : Bukkit.getServer().getWorlds()) { + if (universe.getWorldIDMap().containsKey(world.getUID())) + continue; + // Register and create files for any worlds which did not have files yet. + TownyWorld townyWorld = new TownyWorld(world.getName(), world.getUID()); + universe.registerTownyWorld(townyWorld); + File worldFile = new File(getFileOfTypeWithUUID(TownyDBFileType.WORLD, world.getUID())); + if (!worldFile.exists()) + try { + FileMgmt.mapToFile(townyWorld.getObjectDataMap(), Paths.get(getFileOfTypeWithUUID(TownyDBFileType.WORLD, townyWorld.getUUID()))); } catch (Exception e) { - TownyMessaging.sendErrorMsg(Translation.of("flatfile_err_exception_reading_townblock_file_at_line", path, line)); - return false; + logger.warn("Could not save new world file for TownyWorld: " + townyWorld.getUUID()); + e.printStackTrace(); } - - } else { - TownyMessaging.sendErrorMsg(Translation.of("flatfile_err_townblock_file_unknown_err", path)); - universe.removeTownBlock(townBlock); - deleteTownBlock(townBlock); - } } - - // Some townblocks have had their town name change. Save the townblocks. - if (!toSave.isEmpty()) - toSave.forEach(TownBlock::save); - return true; } - public boolean loadJail(Jail jail) { - String line = ""; - String[] tokens; - String path = getJailFilename(jail); - File jailFile = new File(path); - if (jailFile.exists() && jailFile.isFile()) { - HashMap keys = FileMgmt.loadFileIntoHashMap(jailFile); - - line = keys.get("townblock"); - if (line != null) { - tokens = line.split(","); - WorldCoord wc = null; + @Override + public boolean loadTownBlockList() { + + TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_loading_townblock_list")); + + File townblocksFolder = new File(dataFolderPath + File.separator + "townblocks"); + File[] worldFolders = townblocksFolder.listFiles(File::isDirectory); + TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_folders_found", worldFolders.length)); + boolean mismatched = false; + int mismatchedCount = 0; + try { + for (File worldfolder : worldFolders) { + String worldUUIDAsString = worldfolder.getName(); + UUID worldUUID; try { - wc = new WorldCoord(tokens[0], Integer.parseInt(tokens[1].trim()), Integer.parseInt(tokens[2].trim())); - if (wc.isWilderness() || wc.getTownOrNull() == null) // Not a number format exception but it gets handled the same so why not. - throw new NumberFormatException(); - } catch (NumberFormatException e) { - TownyMessaging.sendErrorMsg("Jail " + jail.getUUID() + " tried to load invalid townblock " + line + " deleting jail."); - removeJail(jail); - deleteJail(jail); - return true; + worldUUID = UUID.fromString(worldUUIDAsString); + } catch (IllegalArgumentException e) { + plugin.getLogger().warning("World folder " + worldfolder + " in TownBlocks folder not readable..."); + continue; + } + if (BukkitTools.getWorld(worldUUID) == null) { + TownyMessaging.sendErrorMsg("Your towny\\data\\townblocks\\ folder contains a folder named '" + + worldUUIDAsString + "' which doesn't correspond to a World UID on your Bukkit server!"); + TownyMessaging.sendErrorMsg("Towny is going to skip loading the townblocks found in this folder."); + continue; } - TownBlock tb = wc.getTownBlockOrNull(); - Town town = tb.getTownOrNull(); - jail.setTownBlock(tb); - jail.setTown(town); - tb.setJail(jail); - town.addJail(jail); - } + TownyWorld world = universe.getWorld(worldUUID); - line = keys.get("spawns"); - if (line != null) { - String[] jails = line.split(";"); - for (String spawn : jails) { - tokens = spawn.split(","); - if (tokens.length >= 4) - try { - jail.addJailCell(Position.deserialize(tokens)); - } catch (IllegalArgumentException e) { - TownyMessaging.sendErrorMsg("Jail " + jail.getUUID() + " tried to load invalid spawn " + line + " skipping."); - } + if (world == null) { + World bukkitWorld = Bukkit.getWorld(worldUUID); + if (bukkitWorld == null) + continue; + universe.newWorld(bukkitWorld); + world = universe.getWorld(worldUUID); } - if (jail.getJailCellCount() == 0) { - TownyMessaging.sendErrorMsg("Jail " + jail.getUUID() + " loaded with zero spawns " + line + " deleting jail."); - removeJail(jail); - deleteJail(jail); - return true; + File worldFolder = new File(dataFolderPath + File.separator + "townblocks" + File.separator + worldUUIDAsString); + File[] townBlockFiles = worldFolder.listFiles(file -> file.getName().endsWith(".data")); + int total = 0; + for (File townBlockFile : townBlockFiles) { + String[] coords = townBlockFile.getName().split("_"); + String[] size = coords[2].split("\\."); + // Do not load a townBlockFile if it does not use teh currently set + // town_block_size. + if (Integer.parseInt(size[0]) != TownySettings.getTownBlockSize()) { + mismatched = true; + mismatchedCount++; + continue; + } + int x = Integer.parseInt(coords[0]); + int z = Integer.parseInt(coords[1]); + TownBlock townBlock = new TownBlock(x, z, world); + universe.addTownBlock(townBlock); + total++; } + TownyMessaging + .sendDebugMsg(Translation.of("flatfile_dbg_world_loaded_townblocks", worldUUIDAsString, total)); } + if (mismatched) + TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_mismatched_townblock_size", mismatchedCount)); + + return true; + } catch (Exception e1) { + e1.printStackTrace(); + return false; } - - return true; } + /* - * Save individual towny objects + * Load individual Towny object-callers */ @Override - public boolean saveResident(Resident resident) { - - List list = new ArrayList<>(); - - list.add("name=" + resident.getName()); - list.add("uuid=" + resident.getUUID()); - - // Last Online - list.add("lastOnline=" + resident.getLastOnline()); - // Registered - list.add("registered=" + resident.getRegistered()); - // Joined Town At - list.add("joinedTownAt=" + resident.getJoinedTownAt()); - // isNPC - list.add("isNPC=" + resident.isNPC()); - - // if they are jailed: - if (resident.isJailed()) { - // jail uuid - list.add("jail=" + resident.getJail().getUUID()); - // jailCell - list.add("jailCell=" + resident.getJailCell()); - // jailHours - list.add("jailHours=" + resident.getJailHours()); - // jailBail - list.add("jailBail=" + resident.getJailBailCost()); - } - - // title - list.add("title=" + resident.getTitle()); - // surname - list.add("surname=" + resident.getSurname()); - // about - if (!TownySettings.getDefaultResidentAbout().equals(resident.getAbout())) - list.add("about=" + resident.getAbout()); - - if (resident.hasTown()) { - list.add("town=" + resident.getTownOrNull().getUUID()); - list.add("town-ranks=" + StringMgmt.join(resident.getTownRanksForSaving(), ",")); - list.add("nation-ranks=" + StringMgmt.join(resident.getNationRanksForSaving(), ",")); - } - - // Friends - list.add("friends=" + StringMgmt.join(toUUIDList(resident.getFriends()), ",")); - list.add(""); + public boolean loadJailUUIDs(Set uuids) throws ObjectCouldNotBeLoadedException { + return loadFlatFilesOfType(TownyDBFileType.JAIL, uuids); + } - // Plot Protection - list.add("protectionStatus=" + resident.getPermissions().toString()); + @Override + public boolean loadPlotGroupUUIDs(Set uuids) throws ObjectCouldNotBeLoadedException { + return loadFlatFilesOfType(TownyDBFileType.PLOTGROUP, uuids); + } - // Metadata - list.add("metadata=" + serializeMetadata(resident)); - /* - * Make sure we only save in async - */ - this.queryQueue.add(new FlatFileSaveTask(list, getResidentFilename(resident))); + @Override + public boolean loadDistrictUUIDs(Set uuids) throws ObjectCouldNotBeLoadedException { + return loadFlatFilesOfType(TownyDBFileType.DISTRICT, uuids); + } - return true; + @Override + public boolean loadResidentUUIDs(Set uuids) throws ObjectCouldNotBeLoadedException { + return loadFlatFilesOfType(TownyDBFileType.RESIDENT, uuids); + } + @Override + public boolean loadTownUUIDs(Set uuids) throws ObjectCouldNotBeLoadedException { + return loadFlatFilesOfType(TownyDBFileType.TOWN, uuids); } - + @Override - public boolean saveHibernatedResident(UUID uuid, long registered) { - List list = new ArrayList<>(); - list.add("registered=" + registered); - this.queryQueue.add(new FlatFileSaveTask(list, getHibernatedResidentFilename(uuid))); - return true; + public boolean loadNationUUIDs(Set uuids) throws ObjectCouldNotBeLoadedException { + return loadFlatFilesOfType(TownyDBFileType.NATION, uuids); } @Override - public boolean saveTown(Town town) { + public boolean loadWorldUUIDs(Set uuids) throws ObjectCouldNotBeLoadedException { + return loadFlatFilesOfType(TownyDBFileType.WORLD, uuids); + } - List list = new ArrayList<>(); + @Override + public boolean loadTownBlocks(Collection townBlocks) throws ObjectCouldNotBeLoadedException { + for (TownBlock townBlock : townBlocks) + if (!loadTownBlock(townBlock)) + throw new ObjectCouldNotBeLoadedException("The Townblock: '" + townBlock.toString() + "' could not be read from the database!"); + return true; + } - // Name - list.add("name=" + town.getName()); + /* + * Return Loadable Objects as Maps for TownyDataBaseHandler to load. + */ - if (town.hasValidUUID()){ - list.add("uuid=" + town.getUUID()); - } else { - list.add("uuid=" + UUID.randomUUID()); - } + @Override + public Map getJailMap(UUID uuid) { + File jailFile = new File(getFileOfTypeWithUUID(TownyDBFileType.JAIL, uuid)); + if (jailFile.exists() && jailFile.isFile()) + return FileMgmt.loadFileIntoHashMap(jailFile); + TownyMessaging.sendErrorMsg("Cannot find a jail file with the UUID " + uuid.toString() + "!"); + return null; + } - // Mayor - final Resident mayor = town.getMayor(); - if (mayor != null) { - list.add("mayor=" + mayor.getUUID()); - list.add("mayorName=" + mayor.getName()); - } - - // Nation - final Nation nation = town.getNationOrNull(); - if (nation != null) { - list.add("nation=" + nation.getUUID()); - list.add("nationName=" + nation.getName()); - } + @Override + public Map getPlotGroupMap(UUID uuid) { + File groupFile = new File(getFileOfTypeWithUUID(TownyDBFileType.PLOTGROUP, uuid)); + if (groupFile.exists() && groupFile.isFile()) + return FileMgmt.loadFileIntoHashMap(groupFile); + TownyMessaging.sendErrorMsg("Cannot find a plotgroup file with the UUID " + uuid.toString() + "!"); + return null; + } - list.add(newLine); - // Town Board - list.add("townBoard=" + town.getBoard()); - // tag - list.add("tag=" + town.getTag()); - // founder - list.add("founder=" + town.getFounder()); - // Town Protection - list.add("protectionStatus=" + town.getPermissions().toString()); - // Bonus Blocks - list.add("bonusBlocks=" + town.getBonusBlocks()); - // Purchased Blocks - list.add("purchasedBlocks=" + town.getPurchasedBlocks()); - // Taxpercent - list.add("taxpercent=" + town.isTaxPercentage()); - // Taxpercent Cap - list.add("maxPercentTaxAmount=" + town.getMaxPercentTaxAmount()); - // Taxes - list.add("taxes=" + town.getTaxes()); - // Plot Price - list.add("plotPrice=" + town.getPlotPrice()); - // Plot Tax - list.add("plotTax=" + town.getPlotTax()); - // Commercial Plot Price - list.add("commercialPlotPrice=" + town.getCommercialPlotPrice()); - // Commercial Tax - list.add("commercialPlotTax=" + town.getCommercialPlotTax()); - // Embassy Plot Price - list.add("embassyPlotPrice=" + town.getEmbassyPlotPrice()); - // Embassy Tax - list.add("embassyPlotTax=" + town.getEmbassyPlotTax()); - // Town Spawn Cost - list.add("spawnCost=" + town.getSpawnCost()); - // Upkeep - list.add("hasUpkeep=" + town.hasUpkeep()); - // UnlimitedClaims - list.add("hasUnlimitedClaims=" + town.hasUnlimitedClaims()); - // VisibleOnTopLists - list.add("visibleOnTopLists=" + town.isVisibleOnTopLists()); - // Open - list.add("open=" + town.isOpen()); - // PVP - list.add("adminDisabledPvP=" + town.isAdminDisabledPVP()); - list.add("adminEnabledPvP=" + town.isAdminEnabledPVP()); - // Mobs override - list.add("adminEnabledMobs=" + town.isAdminEnabledMobs()); - // Allowed to War - list.add("allowedToWar=" + town.isAllowedToWar()); - // Public - list.add("public=" + town.isPublic()); - // Conquered towns setting + date - list.add("conquered=" + town.isConquered()); - list.add("conqueredDays=" + town.getConqueredDays()); - list.add("registered=" + town.getRegistered()); - list.add("joinedNationAt=" + town.getJoinedNationAt()); - list.add("movedHomeBlockAt=" + town.getMovedHomeBlockAt()); - // ForSale - list.add("forSale=" + town.isForSale()); - // Town sale price - list.add("forSalePrice=" + town.getForSalePrice()); - list.add("forSaleTime=" + town.getForSaleTime()); - - // Home Block - if (town.hasHomeBlock()) - try { - list.add("homeBlock=" + town.getHomeBlock().getWorld().getName() + "," + town.getHomeBlock().getX() + "," + town.getHomeBlock().getZ()); - } catch (TownyException ignored) { - } + @Override + public Map getDistrictMap(UUID uuid) { + File districtFile = new File(getFileOfTypeWithUUID(TownyDBFileType.DISTRICT, uuid)); + if (districtFile.exists() && districtFile.isFile()) + return FileMgmt.loadFileIntoHashMap(districtFile); + TownyMessaging.sendErrorMsg("Cannot find a district file with the UUID " + uuid.toString() + "!"); + return null; + } - // Spawn - final Position spawnPos = town.spawnPosition(); - if (spawnPos != null) - list.add("spawn=" + String.join(",", spawnPos.serialize())); + @Override + public Map getResidentMap(UUID uuid) { + File residentFile = new File(getFileOfTypeWithUUID(TownyDBFileType.RESIDENT, uuid)); + if (residentFile.exists() && residentFile.isFile()) + return FileMgmt.loadFileIntoHashMap(residentFile); + TownyMessaging.sendErrorMsg("Cannot find a resident file with the UUID " + uuid.toString() + "!"); + return null; + } - // Outpost Spawns - StringBuilder outpostArray = new StringBuilder("outpostspawns="); - if (town.hasOutpostSpawn()) - for (Position spawn : town.getOutpostSpawns()) { - outpostArray.append(String.join(",", spawn.serialize())).append(";"); - } - list.add(outpostArray.toString()); + @Override + public Map getTownMap(UUID uuid) { + File townFile = new File(getFileOfTypeWithUUID(TownyDBFileType.TOWN, uuid)); + if (townFile.exists() && townFile.isFile()) + return FileMgmt.loadFileIntoHashMap(townFile); + TownyMessaging.sendErrorMsg("Cannot find a town file with the UUID " + uuid.toString() + "!"); + return null; + } - // Outlaws - list.add("outlaws=" + StringMgmt.join(toUUIDList(town.getOutlaws()), ",")); + @Override + public Map getNationMap(UUID uuid) { + File nationFile = new File(getFileOfTypeWithUUID(TownyDBFileType.NATION, uuid)); + if (nationFile.exists() && nationFile.isFile()) + return FileMgmt.loadFileIntoHashMap(nationFile); + TownyMessaging.sendErrorMsg("Cannot find a nation file with the UUID " + uuid.toString() + "!"); + return null; + } - // Metadata - list.add("metadata=" + serializeMetadata(town)); - - // ManualTownLevel - list.add("manualTownLevel=" + town.getManualTownLevel()); - - list.add("ruined=" + town.isRuined()); - list.add("ruinedTime=" + town.getRuinedTime()); - // Peaceful - list.add("neutral=" + town.isNeutral()); - - // Debt balance - list.add("debtBalance=" + town.getDebtBalance()); + @Override + public Map getWorldMap(UUID uuid) { + File worldFile = new File(getFileOfTypeWithUUID(TownyDBFileType.WORLD, uuid)); + if (worldFile.exists() && worldFile.isFile()) + return FileMgmt.loadFileIntoHashMap(worldFile); + TownyMessaging.sendErrorMsg("Cannot find a world file with the UUID " + uuid.toString() + "!"); + return null; + } - // Primary Jail - if (town.getPrimaryJail() != null) - list.add("primaryJail=" + town.getPrimaryJail().getUUID()); - - list.add("trustedResidents=" + StringMgmt.join(toUUIDList(town.getTrustedResidents()), ",")); - list.add("trustedTowns=" + StringMgmt.join(town.getTrustedTownsUUIDS(), ",")); - - list.add("mapColorHexCode=" + town.getMapColorHexCode()); - list.add("nationZoneOverride=" + town.getNationZoneOverride()); - list.add("nationZoneEnabled=" + town.isNationZoneEnabled()); - list.add("allies=" + StringMgmt.join(town.getAlliesUUIDs(), ",")); - list.add("enemies=" + StringMgmt.join(town.getEnemiesUUIDs(), ",")); - list.add("hasActiveWar=" + town.hasActiveWar()); - - /* - * Make sure we only save in async - */ - this.queryQueue.add(new FlatFileSaveTask(list, getTownFilename(town))); + @Override + public Map getTownBlockMap(TownBlock townBlock) { + File fileTownBlock = new File(getTownBlockFilename(townBlock)); + if (fileTownBlock.exists() && fileTownBlock.isFile()) + return FileMgmt.loadFileIntoHashMap(fileTownBlock); + TownyMessaging.sendErrorMsg("Cannot find a townBlock file for " + townBlock.toString() + "!"); + return null; + } - return true; + /* + * Save individual towny objects + */ - } - @Override - public boolean savePlotGroup(PlotGroup group) { - - List list = new ArrayList<>(); - + public boolean saveJail(Jail jail, Map data) { try { - list.add("groupName=" + group.getName()); - list.add("groupPrice=" + group.getPrice()); - list.add("town=" + group.getTown().getUUID()); - list.add("metadata=" + serializeMetadata(group)); + this.queryQueue.add(new FlatFileSaveTask(data, getFileOfTypeWithUUID(TownyDBFileType.JAIL, jail.getUUID()))); + return true; } catch (Exception e) { - plugin.getLogger().log(Level.WARNING, "An exception occurred while saving plot group " + Optional.ofNullable(group).map(g -> g.getUUID().toString()).orElse("null") + ": ", e); + TownyMessaging.sendErrorMsg("FlatFile: Save Jail unknown error " + e.getMessage()); } - - // Save file - this.queryQueue.add(new FlatFileSaveTask(list, getPlotGroupFilename(group))); - - return true; + return false; } @Override - public boolean saveDistrict(District district) { - List list = new ArrayList<>(); - + public boolean savePlotGroup(PlotGroup group, Map data) { try { - list.add("districtName=" + district.getName()); - list.add("town=" + district.getTown().getUUID().toString()); - list.add("metadata=" + serializeMetadata(district)); + this.queryQueue.add(new FlatFileSaveTask(data, getFileOfTypeWithUUID(TownyDBFileType.PLOTGROUP, group.getUUID()))); + return true; } catch (Exception e) { - plugin.getLogger().log(Level.WARNING, "An exception occurred while saving district " + Optional.ofNullable(district).map(g -> g.getUUID().toString()).orElse("null") + ": ", e); + TownyMessaging.sendErrorMsg("FlatFile: Save PlotGroup unknown error " + e.getMessage()); } - - // Save file - this.queryQueue.add(new FlatFileSaveTask(list, getDistrictFilename(district))); - - return true; + return false; } @Override - public boolean saveNation(Nation nation) { - - List list = new ArrayList<>(); - - list.add("name=" + nation.getName()); - - if (nation.hasValidUUID()){ - list.add("uuid=" + nation.getUUID()); - } else { - list.add("uuid=" + UUID.randomUUID()); - } - - if (nation.hasCapital()) { - list.add("capital=" + nation.getCapital().getUUID()); - list.add("capitalName=" + nation.getCapital().getName()); - } - - list.add("nationBoard=" + nation.getBoard()); - - list.add("mapColorHexCode=" + nation.getMapColorHexCode()); - - if (nation.hasTag()) - list.add("tag=" + nation.getTag()); - - list.add("allies=" + StringMgmt.join(toUUIDList(nation.getAllies()), ",")); - - list.add("enemies=" + StringMgmt.join(toUUIDList(nation.getEnemies()), ",")); - - // Taxpercent - list.add("taxpercent=" + nation.isTaxPercentage()); - // Taxpercent Cap - list.add("maxPercentTaxAmount=" + nation.getMaxPercentTaxAmount()); - // Taxes - list.add("taxes=" + nation.getTaxes()); - // Nation Spawn Cost - list.add("spawnCost=" + nation.getSpawnCost()); - // Peaceful - list.add("neutral=" + nation.isNeutral()); - - list.add("registered=" + nation.getRegistered()); - - // Spawn - final Position spawnPos = nation.spawnPosition(); - if (spawnPos != null) { - list.add("nationSpawn=" + String.join(",", spawnPos.serialize())); + public boolean saveDistrict(District district, Map data) { + try { + this.queryQueue.add(new FlatFileSaveTask(data, getFileOfTypeWithUUID(TownyDBFileType.DISTRICT, district.getUUID()))); + return true; + } catch (Exception e) { + TownyMessaging.sendErrorMsg("FlatFile: Save District unknown error " + e.getMessage()); } - - list.add("isPublic=" + nation.isPublic()); - - list.add("isOpen=" + nation.isOpen()); - - // Metadata - list.add("metadata=" + serializeMetadata(nation)); - - list.add("conqueredTax=" + nation.getConqueredTax()); - - // SanctionedTowns - list.add("sanctionedTowns=" + StringMgmt.join(nation.getSanctionedTownsForSaving(), "#")); - // Active War - list.add("hasActiveWar=" + nation.hasActiveWar()); - - list.add("manualNationLevel=" + nation.getManualNationLevel()); - /* - * Make sure we only save in async - */ - this.queryQueue.add(new FlatFileSaveTask(list, getNationFilename(nation))); - - return true; - + return false; } @Override - public boolean saveWorld(TownyWorld world) { - - List list = new ArrayList<>(); - - if (world.getUUID() != null) - list.add("uuid=" + world.getUUID()); - - list.add("name=" + world.getName()); - - // PvP - list.add("pvp=" + world.isPVP()); - // Force PvP - list.add("forcepvp=" + world.isForcePVP()); - // FriendlyFire - list.add("friendlyFire=" + world.isFriendlyFireEnabled()); - // Claimable - list.add("# Can players found towns and claim plots in this world?"); - list.add("claimable=" + world.isClaimable()); - // has monster spawns - list.add("worldmobs=" + world.hasWorldMobs()); - // has wilderness spawns - list.add("wildernessmobs=" + world.hasWildernessMobs()); - // force town mob spawns - list.add("forcetownmobs=" + world.isForceTownMobs()); - // has firespread enabled - list.add("firespread=" + world.isFire()); - list.add("forcefirespread=" + world.isForceFire()); - // has explosions enabled - list.add("explosions=" + world.isExpl()); - list.add("forceexplosions=" + world.isForceExpl()); - // Enderman block protection - list.add("endermanprotect=" + world.isEndermanProtect()); - // CreatureTrample - list.add("disablecreaturetrample=" + world.isDisableCreatureTrample()); - - // Unclaimed - list.add(""); - list.add("# Unclaimed Zone settings."); - - // Unclaimed Zone Build - if (world.getUnclaimedZoneBuild() != null) - list.add("unclaimedZoneBuild=" + world.getUnclaimedZoneBuild()); - // Unclaimed Zone Destroy - if (world.getUnclaimedZoneDestroy() != null) - list.add("unclaimedZoneDestroy=" + world.getUnclaimedZoneDestroy()); - // Unclaimed Zone Switch - if (world.getUnclaimedZoneSwitch() != null) - list.add("unclaimedZoneSwitch=" + world.getUnclaimedZoneSwitch()); - // Unclaimed Zone Item Use - if (world.getUnclaimedZoneItemUse() != null) - list.add("unclaimedZoneItemUse=" + world.getUnclaimedZoneItemUse()); - // Unclaimed Zone Name - if (world.getUnclaimedZoneName() != null) - list.add("unclaimedZoneName=" + world.getUnclaimedZoneName()); - - list.add(""); - list.add("# The following are blocks that will bypass the above build, destroy, switch and itemuse settings."); - - // Unclaimed Zone Ignore Ids - if (world.getUnclaimedZoneIgnoreMaterials() != null) - list.add("unclaimedZoneIgnoreIds=" + StringMgmt.join(world.getUnclaimedZoneIgnoreMaterials(), ",")); - - // PlotManagement Delete - list.add(""); - list.add("# The following settings control what blocks are deleted upon a townblock being unclaimed"); - // Using PlotManagement Delete - list.add("usingPlotManagementDelete=" + world.isUsingPlotManagementDelete()); - // Plot Management Delete Ids - if (world.getPlotManagementDeleteIds() != null) - list.add("plotManagementDeleteIds=" + StringMgmt.join(world.getPlotManagementDeleteIds(), ",")); - - // EntityType removal on unclaim. - list.add(""); - list.add("# The following settings control what EntityTypes are deleted upon a townblock being unclaimed"); - list.add("# Valid EntityTypes are listed here: https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/entity/EntityType.html"); - list.add("isDeletingEntitiesOnUnclaim=" + world.isDeletingEntitiesOnUnclaim()); - if (world.getUnclaimDeleteEntityTypes() != null) - list.add("unclaimDeleteEntityTypes=" + StringMgmt.join(BukkitTools.convertKeyedToString(world.getUnclaimDeleteEntityTypes()), ",")); - - // PlotManagement - list.add(""); - list.add("# The following settings control what blocks are deleted upon a mayor issuing a '/plot clear' command"); - // Using PlotManagement Mayor Delete - list.add("usingPlotManagementMayorDelete=" + world.isUsingPlotManagementMayorDelete()); - // Plot Management Mayor Delete - if (world.getPlotManagementMayorDelete() != null) - list.add("plotManagementMayorDelete=" + StringMgmt.join(world.getPlotManagementMayorDelete(), ",")); - - // PlotManagement Revert - list.add(""); - list.add("# If enabled when a town claims a townblock a snapshot will be taken at the time it is claimed."); - list.add("# When the townblock is unclaimed its blocks will begin to revert to the original snapshot."); - // Using PlotManagement Revert - list.add("usingPlotManagementRevert=" + world.isUsingPlotManagementRevert()); - - list.add("# Any block Id's listed here will not be respawned. Instead it will revert to air. This list also world on the WildRegen settings below."); - // Plot Management Ignore Ids - if (world.getPlotManagementIgnoreIds() != null) - list.add("plotManagementIgnoreIds=" + StringMgmt.join(world.getPlotManagementIgnoreIds(), ",")); - // Revert on Unclaim whitelisted Materials. - if (world.getRevertOnUnclaimWhitelistMaterials() != null) - list.add("revertOnUnclaimWhitelistMaterials=" + StringMgmt.join(world.getRevertOnUnclaimWhitelistMaterials(), "#")); - - // PlotManagement Wild Regen - list.add(""); - list.add("# The following settings control which entities/blocks' explosions are reverted in the wilderness."); - list.add("# If enabled any damage caused by entity explosions will repair itself."); - // Using PlotManagement Wild Regen - list.add("usingPlotManagementWildRegen=" + world.isUsingPlotManagementWildEntityRevert()); - - list.add("# The list of entities whose explosions would be reverted."); - // Wilderness Explosion Protection entities - if (world.getPlotManagementWildRevertEntities() != null) - list.add("PlotManagementWildRegenEntities=" + StringMgmt.join(BukkitTools.convertKeyedToString(world.getPlotManagementWildRevertEntities()), ",")); - - list.add("# If enabled any damage caused by block explosions will repair itself."); - // Using PlotManagement Wild Block Regen - list.add("usingPlotManagementWildRegenBlocks=" + world.isUsingPlotManagementWildBlockRevert()); - - list.add("# The list of blocks whose explosions would be reverted."); - // Wilderness Explosion Protection blocks - if (world.getPlotManagementWildRevertBlocks() != null) - list.add("PlotManagementWildRegenBlocks=" + StringMgmt.join(world.getPlotManagementWildRevertBlocks(), ",")); - - list.add("# The list of blocks to regenerate. (if empty all blocks will regenerate)"); - // Wilderness Explosion Protection entities - if (world.getPlotManagementWildRevertBlockWhitelist() != null) - list.add("PlotManagementWildRegenBlockWhitelist=" + StringMgmt.join(world.getPlotManagementWildRevertBlockWhitelist(), ",")); - - list.add("# The list of blocks to that should not get replaced when an explosion is reverted in the wilderness, ie: a chest placed in a creeper hole that is reverting."); - // Wilderness Explosion materials to not overwrite. - if (world.getWildRevertMaterialsToNotOverwrite() != null) - list.add("wildRegenBlocksToNotOverwrite=" + StringMgmt.join(world.getWildRevertMaterialsToNotOverwrite(), ",")); - - list.add("# The delay after which the explosion reverts will begin."); - // Using PlotManagement Wild Regen Delay - list.add("usingPlotManagementWildRegenDelay=" + world.getPlotManagementWildRevertDelay()); - - - // Using Towny - list.add(""); - list.add("# This setting is used to enable or disable Towny in this world."); - // Using Towny - list.add("usingTowny=" + world.isUsingTowny()); - - // is War allowed - list.add(""); - list.add("# This setting is used to enable or disable Event war in this world."); - list.add("warAllowed=" + world.isWarAllowed()); - - // jailing - list.add("jailing=" + world.isJailingEnabled()); - - // Metadata - list.add(""); - list.add("metadata=" + serializeMetadata(world)); - + public boolean saveResident(Resident resident, Map data) { /* - * Make sure we only save in async + * Make sure we only save in async */ - this.queryQueue.add(new FlatFileSaveTask(list, getWorldFilename(world))); - - return true; - + try { + this.queryQueue.add(new FlatFileSaveTask(data, getFileOfTypeWithUUID(TownyDBFileType.RESIDENT, resident.getUUID()))); + return true; + } catch (Exception e) { + TownyMessaging.sendErrorMsg("FlatFile: Save Resident unknown error " + e.getMessage()); + } + return false; } @Override - public boolean saveTownBlock(TownBlock townBlock) { - - if (!townBlock.hasTown()) - return false; - - FileMgmt.checkOrCreateFolder(dataFolderPath + File.separator + "townblocks" + File.separator + townBlock.getWorld().getName()); - - List list = new ArrayList<>(); - - // name - list.add("name=" + townBlock.getName()); - - // price - list.add("price=" + townBlock.getPlotPrice()); - - // taxed - list.add("taxed=" + townBlock.isTaxed()); - - list.add("town=" + townBlock.getTownOrNull().getUUID()); - - // resident - if (townBlock.hasResident()) - list.add("resident=" + townBlock.getResidentOrNull().getUUID()); - - // type - list.add("type=" + townBlock.getTypeName()); - - // outpost - list.add("outpost=" + townBlock.isOutpost()); - - /* - * Only include a permissions line IF the plot perms are custom. - */ - if (townBlock.isChanged()) { - // permissions - list.add("permissions=" + townBlock.getPermissions().toString()); - } - - // Have permissions been manually changed - list.add("changed=" + townBlock.isChanged()); - - list.add("claimedAt=" + townBlock.getClaimedAt()); - - if (townBlock.hasMinTownMembershipDays()) - list.add("minTownMembershipDays=" + townBlock.getMinTownMembershipDays()); - - if (townBlock.hasMaxTownMembershipDays()) - list.add("maxTownMembershipDays=" + townBlock.getMaxTownMembershipDays()); - - // Metadata - list.add("metadata=" + serializeMetadata(townBlock)); - - // Group ID - StringBuilder groupID = new StringBuilder(); - if (townBlock.hasPlotObjectGroup()) { - groupID.append(townBlock.getPlotObjectGroup().getUUID()); + public boolean saveHibernatedResident(UUID uuid, Map data) { + try { + this.queryQueue.add(new FlatFileSaveTask(data, getFileOfTypeWithUUID(TownyDBFileType.HIBERNATED_RESIDENT, uuid))); + return true; + } catch (Exception e) { + TownyMessaging.sendErrorMsg("FlatFile: Save Hibernated Resident unknown error " + e.getMessage()); } - - list.add("groupID=" + groupID); + return false; + } - // District ID - StringBuilder districtID = new StringBuilder(); - if (townBlock.hasDistrict()) { - districtID.append(townBlock.getDistrict().getUUID()); + @Override + public boolean saveTown(Town town, Map data) { + try { + this.queryQueue.add(new FlatFileSaveTask(data, getFileOfTypeWithUUID(TownyDBFileType.TOWN, town.getUUID()))); + return true; + } catch (Exception e) { + TownyMessaging.sendErrorMsg("FlatFile: Save Town unknown error " + e.getMessage()); } - - list.add("districtID=" + districtID); + return false; + } - if (townBlock.hasTrustedResidents()) { - list.add("trustedResidents=" + StringMgmt.join(toUUIDList(townBlock.getTrustedResidents()), ",")); + @Override + public boolean saveNation(Nation nation, Map data) { + try { + this.queryQueue.add(new FlatFileSaveTask(data, getFileOfTypeWithUUID(TownyDBFileType.NATION, nation.getUUID()))); + return true; + } catch (Exception e) { + TownyMessaging.sendErrorMsg("FlatFile: Save Nation unknown error " + e.getMessage()); } - - if (townBlock.hasPermissionOverrides()) { - Map stringMap = new HashMap<>(); - for (Map.Entry entry : townBlock.getPermissionOverrides().entrySet()) { - stringMap.put(entry.getKey().getUUID().toString(), entry.getValue().toString()); - } + return false; + } - list.add("customPermissionData=" + new Gson().toJson(stringMap)); + @Override + public boolean saveWorld(TownyWorld world, Map data) { + try { + this.queryQueue.add(new FlatFileSaveTask(data, getFileOfTypeWithUUID(TownyDBFileType.WORLD, world.getUUID()))); + return true; + } catch (Exception e) { + TownyMessaging.sendErrorMsg("FlatFile: Save World unknown error " + e.getMessage()); } - - /* - * Make sure we only save in async - */ - this.queryQueue.add(new FlatFileSaveTask(list, getTownBlockFilename(townBlock))); - - return true; - + return false; } - public boolean saveJail(Jail jail) { - - List list = new ArrayList<>(); - - list.add("townblock=" + jail.getTownBlock().getWorldCoord().toString()); - StringBuilder jailArray = new StringBuilder("spawns="); - for (Position spawn : jail.getJailCellPositions()) { - jailArray.append(String.join(",", spawn.serialize())) - .append(";"); + @Override + public boolean saveTownBlock(TownBlock townBlock, Map data) { + try { + this.queryQueue.add(new FlatFileSaveTask(data, getTownBlockFilename(townBlock))); + return true; + } catch (Exception e) { + TownyMessaging.sendErrorMsg("FlatFile: Save TownBlock unknown error " + e.getMessage()); } - - list.add(jailArray.toString()); - - this.queryQueue.add(new FlatFileSaveTask(list, getJailFilename(jail))); - return true; + return false; } - + /* * Delete objects */ - + + // Private FlatFile method for deleting database objects. + private void deleteFileByTypeAndUUID(TownyDBFileType type, UUID uuid) { + File file = new File(getFileOfTypeWithUUID(type, uuid)); + queryQueue.add(new DeleteFileTask(file, false)); + } + + // Private FlatFile method for deleting legacy database objects keyed by names. + void deleteFileByTypeAndName(TownyDBFileType type, String name) { + File file = new File(getFileOfTypeWithName(type, name)); + queryQueue.add(new DeleteFileTask(file, false)); + } + @Override public void deleteResident(Resident resident) { - File file = new File(getResidentFilename(resident)); - queryQueue.add(new DeleteFileTask(file, false)); + deleteFileByTypeAndUUID(TownyDBFileType.RESIDENT, resident.getUUID()); } - @Override + @Override public void deleteHibernatedResident(UUID uuid) { - File file = new File(getHibernatedResidentFilename(uuid)); - queryQueue.add(new DeleteFileTask(file, true)); + deleteFileByTypeAndUUID(TownyDBFileType.HIBERNATED_RESIDENT, uuid); } - + @Override public void deleteTown(Town town) { - File file = new File(getTownFilename(town)); - queryQueue.add(new DeleteFileTask(file, false)); + deleteFileByTypeAndUUID(TownyDBFileType.TOWN, town.getUUID()); } @Override public void deleteNation(Nation nation) { - File file = new File(getNationFilename(nation)); - queryQueue.add(new DeleteFileTask(file, false)); + deleteFileByTypeAndUUID(TownyDBFileType.NATION, nation.getUUID()); } @Override public void deleteWorld(TownyWorld world) { - File file = new File(getWorldFilename(world)); - queryQueue.add(new DeleteFileTask(file, false)); + deleteFileByTypeAndUUID(TownyDBFileType.WORLD, world.getUUID()); } @Override public void deleteTownBlock(TownBlock townBlock) { File file = new File(getTownBlockFilename(townBlock)); - if (!file.exists()) - return; - - // TownBlocks can end up being deleted because they do not contain valid towns. - // This will move a deleted townblock to either: - // towny\townblocks\worldname\deleted\townname folder, or the - // towny\townblocks\worldname\deleted\ folder if there is not valid townname. - queryQueue.add(() -> FileMgmt.moveTownBlockFile(file, "deleted", townBlock.hasTown() ? townBlock.getTownOrNull().getName() : "")); + + queryQueue.add(() -> { + if (file.exists()) { + // TownBlocks can end up being deleted because they do not contain valid towns. + // This will move a deleted townblock to either: + // towny\townblocks\worldname\deleted\townname folder, or the + // towny\townblocks\worldname\deleted\ folder if there is not valid townname. + String name = null; + try { + name = townBlock.getTown().getUUID().toString(); + } catch (NotRegisteredException ignored) { + } + if (name != null) + FileMgmt.moveTownBlockFile(file, "deleted", name); + else + FileMgmt.moveTownBlockFile(file, "deleted", ""); + } + }); } - + @Override public void deletePlotGroup(PlotGroup group) { - File file = new File(getPlotGroupFilename(group)); - queryQueue.add(new DeleteFileTask(file, false)); + deleteFileByTypeAndUUID(TownyDBFileType.PLOTGROUP, group.getUUID()); } - + @Override public void deleteDistrict(District district) { - File file = new File(getDistrictFilename(district)); - queryQueue.add(new DeleteFileTask(file, false)); + deleteFileByTypeAndUUID(TownyDBFileType.DISTRICT, district.getUUID()); } @Override public void deleteJail(Jail jail) { - File file = new File(getJailFilename(jail)); - queryQueue.add(new DeleteFileTask(file, false)); + deleteFileByTypeAndUUID(TownyDBFileType.JAIL, jail.getUUID()); } @Override public CompletableFuture> getHibernatedResidentRegistered(UUID uuid) { return CompletableFuture.supplyAsync(() -> { - File hibernatedFile = new File(getHibernatedResidentFilename(uuid)); + File hibernatedFile = new File(getFileOfTypeWithUUID(TownyDBFileType.HIBERNATED_RESIDENT, uuid)); if (!hibernatedFile.exists()) return Optional.empty(); @@ -2811,4 +729,5 @@ private NameAndId loadNameAndUUIDFromFile(File file, String fileName, String des final UUID uuid = super.parseUUIDOrNew(possibleUUID, describedAs + " '" + name + "'"); return new NameAndId(name, uuid); } + } diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/db/TownySQLSource.java b/Towny/src/main/java/com/palmergames/bukkit/towny/db/TownySQLSource.java index beafce3536b..63ff09220ca 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/db/TownySQLSource.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/db/TownySQLSource.java @@ -5,44 +5,28 @@ */ package com.palmergames.bukkit.towny.db; -import com.google.gson.Gson; -import com.google.gson.reflect.TypeToken; import com.palmergames.bukkit.towny.Towny; -import com.palmergames.bukkit.towny.TownyAPI; import com.palmergames.bukkit.towny.TownyMessaging; import com.palmergames.bukkit.towny.TownySettings; import com.palmergames.bukkit.towny.TownyUniverse; -import com.palmergames.bukkit.towny.event.DeleteNationEvent; -import com.palmergames.bukkit.towny.exceptions.AlreadyRegisteredException; -import com.palmergames.bukkit.towny.exceptions.EmptyNationException; -import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; -import com.palmergames.bukkit.towny.exceptions.TownyException; +import com.palmergames.bukkit.towny.exceptions.ObjectCouldNotBeLoadedException; import com.palmergames.bukkit.towny.exceptions.initialization.TownyInitException; import com.palmergames.bukkit.towny.object.District; +import com.palmergames.bukkit.towny.object.NameAndId; import com.palmergames.bukkit.towny.object.Nation; -import com.palmergames.bukkit.towny.object.PermissionData; import com.palmergames.bukkit.towny.object.PlotGroup; -import com.palmergames.bukkit.towny.object.Position; import com.palmergames.bukkit.towny.object.Resident; import com.palmergames.bukkit.towny.object.Town; import com.palmergames.bukkit.towny.object.TownBlock; -import com.palmergames.bukkit.towny.object.TownBlockTypeHandler; import com.palmergames.bukkit.towny.object.TownyWorld; -import com.palmergames.bukkit.towny.object.WorldCoord; -import com.palmergames.bukkit.towny.object.metadata.MetadataLoader; import com.palmergames.bukkit.towny.object.jail.Jail; import com.palmergames.bukkit.towny.tasks.CooldownTimerTask; -import com.palmergames.bukkit.towny.utils.MapUtil; -import com.palmergames.bukkit.util.BukkitTools; import com.palmergames.util.FileMgmt; -import com.palmergames.util.JavaUtil; import com.palmergames.util.Pair; -import com.palmergames.util.StringMgmt; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.pool.HikariPool; -import org.bukkit.Bukkit; import org.bukkit.World; import org.jetbrains.annotations.ApiStatus; @@ -52,10 +36,12 @@ import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; +import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; @@ -63,10 +49,11 @@ import java.util.Locale; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; import java.util.logging.Level; -import java.util.stream.Collectors; public final class TownySQLSource extends TownyDatabaseHandler { private final String tb_prefix; @@ -411,11 +398,11 @@ public enum TownyDBTableType { JAIL("JAILS", "SELECT uuid FROM ", "uuid"), PLOTGROUP("PLOTGROUPS", "SELECT groupID FROM ", "groupID"), DISTRICT("DISTRICTS", "SELECT uuid FROM ", "uuid"), - RESIDENT("RESIDENTS", "SELECT name FROM ", "name"), + RESIDENT("RESIDENTS", "SELECT uuid, name FROM ", "uuid"), HIBERNATED_RESIDENT("HIBERNATEDRESIDENTS", "", "uuid"), - TOWN("TOWNS", "SELECT name FROM ", "name"), - NATION("NATIONS", "SELECT name FROM ", "name"), - WORLD("WORLDS", "SELECT name FROM ", "name"), + TOWN("TOWNS", "SELECT uuid, name FROM ", "uuid"), + NATION("NATIONS", "SELECT uuid, name FROM ", "uuid"), + WORLD("WORLDS", "SELECT uuid, name FROM ", "uuid"), TOWNBLOCK("TOWNBLOCKS", "SELECT world,x,z FROM ", "name"), COOLDOWN("COOLDOWNS", "SELECT * FROM ", "key"); @@ -453,2298 +440,474 @@ public String getLoadErrorMsg(UUID uuid) { } } - /* - * Load keys - */ - - @Override - public boolean loadTownBlockList() { - TownyMessaging.sendDebugMsg("Loading TownBlock List"); - - try (Connection connection = getConnection(); - Statement s = connection.createStatement(); - ResultSet rs = s.executeQuery("SELECT world,x,z FROM " + tb_prefix + "TOWNBLOCKS")) { - - int total = 0; - while (rs.next()) { - String worldName = rs.getString("world"); - TownyWorld world = universe.getWorld(worldName); - if (world == null) - throw new Exception("World " + worldName + " not registered!"); + private boolean loadResultSetListOfType(TownyDBTableType type, Consumer consumer) { + TownyMessaging.sendDebugMsg("Searching for " + type.tableName.toLowerCase(Locale.ROOT) + "..."); + if (!isReady()) + return false; + + try { + try (Statement s = getConnection().createStatement()) { + ResultSet rs = s.executeQuery(type.queryString + tb_prefix + type.tableName); + if (rs.getFetchSize() != 0) + TownyMessaging.sendDebugMsg("Loading " + rs.getFetchSize() + " entries from the " + type.tableName + " table..."); + + while (rs.next()) { + UUID uuid = UUID.fromString(rs.getString(type.primaryKey)); + String name = null; + try { + name = rs.getString("name"); + } catch (SQLException ignored) {} // Some data types do not store a name. - int x = Integer.parseInt(rs.getString("x")); - int z = Integer.parseInt(rs.getString("z")); + // Residents that are NPCs can have special UUID versions applied to them. + if (type.equals(TownyDBTableType.RESIDENT) && name != null) + uuid = super.parsePlayerUUID(uuid.toString(), name); - TownBlock townBlock = new TownBlock(x, z, world); - universe.addTownBlock(townBlock); - total++; + consumer.accept(new NameAndId(name, uuid)); + } } - - TownyMessaging.sendDebugMsg("Loaded " + total + " townblocks."); - + return true; } catch (SQLException s) { - plugin.getLogger().warning("SQL: town block list error: " + s.getMessage()); + s.printStackTrace(); } catch (Exception e) { - plugin.getLogger().log(Level.WARNING, "SQL: townblock list unknown error", e); + TownyMessaging.sendErrorMsg(e.getMessage()); } return false; + } + private boolean loadResultSetOfType(TownyDBTableType type, Set UUIDs) throws ObjectCouldNotBeLoadedException { + for (UUID uuid : UUIDs) + if (!loadResultSet(type, uuid)) + throw new ObjectCouldNotBeLoadedException(type.getLoadErrorMsg(uuid)); + return true; } - @Override - public boolean loadResidentList() { - TownyMessaging.sendDebugMsg("Loading Resident List"); + /* + * Load keys + */ - try (Connection connection = getConnection(); - Statement s = connection.createStatement(); - ResultSet rs = s.executeQuery("SELECT name, uuid FROM " + tb_prefix + "RESIDENTS")) { - - while (rs.next()) { - final String name = rs.getString("name"); - final UUID uuid = super.parsePlayerUUID(rs.getString("uuid"), name); - - if (uuid == null) { - plugin.getLogger().warning("Resident '" + name + "' does not have a valid uuid and cannot be loaded."); - continue; - } + @Override + public boolean loadJailList() { + return loadResultSetListOfType(TownyDBTableType.JAIL, nameAndId -> universe.newJailInternal(nameAndId.uuid())); + } - try { - newResident(name, uuid); - } catch (AlreadyRegisteredException e) { - final Resident otherResident = universe.getResident(uuid); - if (otherResident != null && !otherResident.getName().equals(name)) { - // UUID is already registered - super.pendingDuplicateResidents.add(Pair.pair(name, otherResident.getName())); - } + @Override + public boolean loadPlotGroupList() { + return loadResultSetListOfType(TownyDBTableType.PLOTGROUP, nameAndId -> universe.newPlotGroupInternal(nameAndId.uuid())); + } + + @Override + public boolean loadDistrictList() { + return loadResultSetListOfType(TownyDBTableType.DISTRICT, nameAndId -> universe.newDistrictInternal(nameAndId.uuid())); + } + + @Override + public boolean loadResidentList() { + return loadResultSetListOfType(TownyDBTableType.RESIDENT, nameAndId -> { + if (!universe.hasResident(nameAndId.uuid())) + universe.newResidentInternal(nameAndId.name(), nameAndId.uuid()); + else { + final Resident otherResident = universe.getResident(nameAndId.uuid()); + if (otherResident != null && !otherResident.getName().equals(nameAndId.name())) { + // UUID is already registered + super.pendingDuplicateResidents.add(Pair.pair(nameAndId.name(), otherResident.getName())); } } - return true; - } catch (Exception e) { - plugin.getLogger().log(Level.WARNING, "SQL: resident list unknown error", e); - } - return false; + }); } @Override public boolean loadTownList() { - TownyMessaging.sendDebugMsg("Loading Town List"); - - try (Connection connection = getConnection(); - Statement s = connection.createStatement(); - ResultSet rs = s.executeQuery("SELECT name, uuid FROM " + tb_prefix + "TOWNS")) { - - while (rs.next()) { - final String name = rs.getString("name"); - - try { - universe.newTownInternal(name, super.parseUUIDOrNew(rs.getString("uuid"), "town '" + name + "'")); - } catch (AlreadyRegisteredException ignored) {} - } - return true; - } catch (SQLException e) { - TownyMessaging.sendErrorMsg("SQL: town list sql error : " + e.getMessage()); - } catch (Exception e) { - plugin.getLogger().log(Level.WARNING, "SQL: town list unknown error", e); - } - return false; + return loadResultSetListOfType(TownyDBTableType.TOWN, nameAndId -> universe.newTownInternal(nameAndId.name(), nameAndId.uuid())); } @Override public boolean loadNationList() { - TownyMessaging.sendDebugMsg("Loading Nation List"); - - try (Connection connection = getConnection(); - Statement s = connection.createStatement(); - ResultSet rs = s.executeQuery("SELECT name, uuid FROM " + tb_prefix + "NATIONS")) { - - while (rs.next()) { - final String name = rs.getString("name"); - - try { - newNation(name, super.parseUUIDOrNew(rs.getString("uuid"), "nation '" + name + "'")); - } catch (AlreadyRegisteredException ignored) {} - } - return true; - } catch (SQLException e) { - TownyMessaging.sendErrorMsg("SQL: nation list sql error : " + e.getMessage()); - } catch (Exception e) { - plugin.getLogger().log(Level.WARNING, "SQL: nation list unknown error", e); - } - return false; + return loadResultSetListOfType(TownyDBTableType.NATION, nameAndId -> universe.newNationInternal(nameAndId.name(), nameAndId.uuid())); } - + @Override public boolean loadWorldList() { - TownyMessaging.sendDebugMsg("Loading World List"); + loadResultSetListOfType(TownyDBTableType.WORLD, nameAndId -> universe.newWorldInternal(nameAndId.name(), nameAndId.uuid())); + for (World world : plugin.getServer().getWorlds()) { + if (universe.getWorldIDMap().containsKey(world.getUID())) + continue; - // Check for any new worlds registered with bukkit. - for (World world : Bukkit.getServer().getWorlds()) - universe.registerTownyWorld(new TownyWorld(world.getName(), world.getUID())); - - try (Connection connection = getConnection(); - Statement s = connection.createStatement(); - ResultSet rs = s.executeQuery("SELECT name, uuid FROM " + tb_prefix + "WORLDS")) { - - while (rs.next()) { - final String name = rs.getString("name"); - - // World is loaded in bukkit and got registered by the newWorld above. - if (universe.getWorld(name) != null) - continue; - - UUID uuid = null; - try { - uuid = UUID.fromString(rs.getString("uuid")); - } catch (IllegalArgumentException | NullPointerException | SQLException ignored) {} - - if (uuid != null) { - universe.registerTownyWorld(new TownyWorld(rs.getString("name"), uuid)); - } else { - try { - newWorld(rs.getString("name")); - } catch (AlreadyRegisteredException ignored) {} - } + // Register and create rows for any worlds which did not have files yet. + TownyWorld townyWorld = new TownyWorld(world.getName(), world.getUID()); + universe.registerTownyWorld(townyWorld); + try { + queueUpdateDB("WORLDS", townyWorld.getObjectDataMap(), null); + } catch (Exception e) { + logger.warn("Could not save new world row for TownyWorld: " + townyWorld.getUUID()); + e.printStackTrace(); } - } catch (SQLException e) { - TownyMessaging.sendErrorMsg("SQL: world list sql error : " + e.getMessage()); - } catch (Exception e) { - plugin.getLogger().log(Level.WARNING, "SQL: world list unknown error", e); } - return true; } - - public boolean loadPlotGroupList() { - TownyMessaging.sendDebugMsg("Loading PlotGroup List"); - - try (Connection connection = getConnection(); - Statement s = connection.createStatement(); - ResultSet rs = s.executeQuery("SELECT groupID FROM " + tb_prefix + "PLOTGROUPS")) { - while (rs.next()) { - try { - universe.newPlotGroupInternal(UUID.fromString(rs.getString("groupID"))); - } catch (IllegalArgumentException e) { - plugin.getLogger().log(Level.WARNING, "ID for plot group is not a valid uuid, skipped loading plot group {}", rs.getString("groupID")); - } - } - - return true; - - } catch (SQLException e) { - plugin.getLogger().log(Level.SEVERE, "An exception occurred while loading plot group list", e); - } - - return false; - } - @Override - public boolean loadDistrictList() { - TownyMessaging.sendDebugMsg("Loading District List"); + public boolean loadTownBlockList() { + TownyMessaging.sendDebugMsg("Loading TownBlock List"); try (Connection connection = getConnection(); Statement s = connection.createStatement(); - ResultSet rs = s.executeQuery("SELECT uuid FROM " + tb_prefix + "DISTRICTS")) { - + ResultSet rs = s.executeQuery("SELECT world,x,z FROM " + tb_prefix + "TOWNBLOCKS")) { + + int total = 0; while (rs.next()) { - try { - universe.newDistrictInternal(UUID.fromString(rs.getString("uuid"))); - } catch (IllegalArgumentException e) { - plugin.getLogger().log(Level.WARNING, "ID for district is not a valid uuid, skipped loading district {}", rs.getString("uuid")); - } - } - - return true; - - } catch (SQLException e) { - plugin.getLogger().log(Level.SEVERE, "An exception occurred while loading district list", e); - } - - return false; - } + String worldName = rs.getString("world"); + TownyWorld world = universe.getWorld(worldName); + if (world == null) + throw new Exception("World " + worldName + " not registered!"); - public boolean loadJailList() { - TownyMessaging.sendDebugMsg("Loading Jail List"); + int x = Integer.parseInt(rs.getString("x")); + int z = Integer.parseInt(rs.getString("z")); - try (Connection connection = getConnection(); - Statement s = connection.createStatement(); - ResultSet rs = s.executeQuery("SELECT uuid FROM " + tb_prefix + "JAILS")) { - - while (rs.next()) { - universe.newJailInternal(rs.getString("uuid")); + TownBlock townBlock = new TownBlock(x, z, world); + universe.addTownBlock(townBlock); + total++; } + TownyMessaging.sendDebugMsg("Loaded " + total + " townblocks."); + return true; + } catch (SQLException s) { + plugin.getLogger().warning("SQL: town block list error: " + s.getMessage()); } catch (Exception e) { - plugin.getLogger().log(Level.SEVERE, "An exception occurred while loading jail list", e); + plugin.getLogger().log(Level.WARNING, "SQL: townblock list unknown error", e); } - return false; - } - - /* - * Load individual towny object - */ - - @Override - public boolean loadResidents() { - TownyMessaging.sendDebugMsg("Loading Residents"); - - try (Connection connection = getConnection(); - Statement s = connection.createStatement(); - ResultSet rs = s.executeQuery("SELECT * FROM " + tb_prefix + "RESIDENTS")) { - - while (rs.next()) { - String residentName; - try { - residentName = rs.getString("name"); - } catch (SQLException ex) { - plugin.getLogger().log(Level.SEVERE, "Loading Error: Error fetching a resident name from SQL Database. Skipping loading resident..", ex); - continue; - } - - Resident resident = universe.getResident(residentName); - - if (resident == null) { - plugin.getLogger().severe(String.format("Loading Error: Could not fetch resident '%s' from Towny universe while loading from SQL DB.", residentName)); - continue; - } - - if (!loadResident(resident, rs)) { - plugin.getLogger().severe("Loading Error: Could not read resident data '" + resident.getName() + "'."); - return false; - } - } - } catch (SQLException e) { - TownyMessaging.sendErrorMsg("SQL: Load resident sql error : " + e.getMessage()); - } - return true; } - @Override - public boolean loadResident(Resident resident) { - - /* - * Never called in SQL setups. - */ - return true; - + private boolean loadResultSet(TownyDBTableType type, UUID uuid) { + return switch (type) { + case JAIL -> loadJailData(uuid); + case NATION -> loadNationData(uuid); + case PLOTGROUP -> loadPlotGroupData(uuid); + case DISTRICT -> loadDistrictData(uuid); + case RESIDENT -> loadResidentData(uuid); + case TOWN -> loadTownData(uuid); + case TOWNBLOCK -> throw new UnsupportedOperationException("Unimplemented case: " + type); + case WORLD -> loadWorldData(uuid); + default -> throw new IllegalArgumentException("Unexpected value: " + type); + }; } - private boolean loadResident(Resident resident, ResultSet rs) { - try { - String search; - - try { - resident.setLastOnline(rs.getLong("lastOnline")); - } catch (SQLException e) { - plugin.getLogger().log(Level.WARNING, "Could not get lastOnline column on the residents table", e); - } - - try { - resident.setRegistered(rs.getLong("registered")); - } catch (SQLException e) { - plugin.getLogger().log(Level.WARNING, "Could not get registered column on the residents table", e); - } - - try { - resident.setJoinedTownAt(rs.getLong("joinedTownAt")); - } catch (SQLException e) { - plugin.getLogger().log(Level.WARNING, "Could not get joinedTownAt column on the residents table", e); - } - - try { - resident.setNPC(rs.getBoolean("isNPC")); - } catch (SQLException e) { - plugin.getLogger().log(Level.WARNING, "Could not get isNPC column on the residents table", e); - } - - if (rs.getString("jailUUID") != null && !rs.getString("jailUUID").isEmpty()) { - UUID uuid = UUID.fromString(rs.getString("jailUUID")); - if (universe.hasJail(uuid)) { - resident.setJail(universe.getJail(uuid)); - } - } - - if (resident.isJailed()) { - try { - if (rs.getString("jailCell") != null && !rs.getString("jailCell").isEmpty()) - resident.setJailCell(rs.getInt("jailCell")); - } catch (SQLException e) { - plugin.getLogger().log(Level.WARNING, "Could not get jailCell column on the residents table", e); - } - - try { - if (rs.getString("jailHours") != null && !rs.getString("jailHours").isEmpty()) - resident.setJailHours(rs.getInt("jailHours")); - } catch (SQLException e) { - plugin.getLogger().log(Level.WARNING, "Could not get jailHours column on the residents table", e); - } - - try { - if (rs.getString("jailBail") != null && !rs.getString("jailBail").isEmpty()) - resident.setJailBailCost(rs.getDouble("jailBail")); - } catch (SQLException e) { - plugin.getLogger().log(Level.WARNING, "Could not get jailBail column on the residents table", e); - } - } - - String line; - try { - line = rs.getString("about"); - if (line != null) - resident.setAbout(line); - } catch (SQLException e) { - plugin.getLogger().log(Level.WARNING, "Could not get about column on the residents table", e); - } - - try { - line = rs.getString("friends"); - if (line != null) { - search = (line.contains("#")) ? "#" : ","; - - final String[] split = line.split(search); - final UUID[] friendUUIDs = toUUIDArray(split); - - List friends = friendUUIDs.length > 0 ? api.getResidents(friendUUIDs) : api.getResidents(split); - for (Resident friend : friends) { - resident.addFriend(friend); - } - } - } catch (SQLException e) { - plugin.getLogger().log(Level.WARNING, "Could not get friends column on the residents table", e); - } - - try { - resident.setPermissions(rs.getString("protectionStatus").replaceAll("#", ",")); - } catch (SQLException e) { - plugin.getLogger().log(Level.WARNING, "Could not get protectionStatus column on the residents table", e); - } - - try { - line = rs.getString("metadata"); - if (line != null && !line.isEmpty()) { - MetadataLoader.getInstance().deserializeMetadata(resident, line); - } - } catch (SQLException ignored) { - } - - line = rs.getString("town"); - if ((line != null) && (!line.isEmpty())) { - final UUID townUUID = JavaUtil.parseUUIDOrNull(line); - - Town town = townUUID != null ? universe.getTown(townUUID) : universe.getTown(line); - if (town == null) { - TownyMessaging.sendErrorMsg("Loading Error: " + resident.getName() + " tried to load the town " + line + " which is invalid, removing town from the resident."); - resident.setTown(null, false); - } - else { - resident.setTown(town, false); - - try { - resident.setTitle(rs.getString("title")); - } catch (SQLException e) { - plugin.getLogger().log(Level.WARNING, "Could not get title column on the residents table", e); - } - try { - resident.setSurname(rs.getString("surname")); - } catch (SQLException e) { - plugin.getLogger().log(Level.WARNING, "Could not get surname column on the residents table", e); - } + private Map loadResultSetIntoMap(ResultSet rs) throws SQLException { + Map keys = new HashMap<>(); + ResultSetMetaData md = rs.getMetaData(); + int columns = md.getColumnCount(); + for (int i = 1; i <= columns; ++i) + keys.put(md.getColumnName(i), rs.getString(i)); - try { - line = rs.getString("town-ranks"); - if ((line != null) && (!line.isEmpty())) { - search = (line.contains("#")) ? "#" : ","; - resident.setTownRanks(Arrays.asList((line.split(search)))); - } - } catch (Exception ignored) {} - - try { - line = rs.getString("nation-ranks"); - if ((line != null) && (!line.isEmpty())) { - search = (line.contains("#")) ? "#" : ","; - resident.setNationRanks(Arrays.asList((line.split(search)))); - } - } catch (Exception ignored) {} - } - } - return true; - } catch (SQLException e) { - TownyMessaging.sendErrorMsg("SQL: Load resident sql error : " + e.getMessage()); - } catch (Exception e) { - plugin.getLogger().log(Level.WARNING, "SQL: Load resident unknown error", e); - } - return false; + return keys; } - @Override - public boolean loadTowns() { - TownyMessaging.sendDebugMsg("Loading Towns"); - - try (Connection connection = getConnection(); - Statement s = connection.createStatement(); - ResultSet rs = s.executeQuery("SELECT * FROM " + tb_prefix + "TOWNS ")) { - while (rs.next()) { - String townName; - try { - townName = rs.getString("name"); - } catch (SQLException ex) { - plugin.getLogger().log(Level.SEVERE, "Loading Error: Error fetching a town name from SQL Database. Skipping loading town..", ex); - continue; - } - Town town = universe.getTown(townName); - if (town == null) { - plugin.getLogger().severe(String.format("Loading Error: Could not fetch town '%s' from Towny universe while loading from SQL DB.", townName)); - continue; - } - - if (!loadTown(rs)) { - plugin.getLogger().warning("Loading Error: Could not read town data properly."); - return false; - } - } - } catch (SQLException e) { - TownyMessaging.sendErrorMsg("SQL: Load Town sql Error - " + e.getMessage()); - return false; - } - - return true; - } - - @Override - public boolean loadTown(Town town) { - - /* - * Never called in SQL setups. - */ - return true; - - } - - private boolean loadTown(ResultSet rs) { - String line; - String[] tokens; - String search; - String name = null; - try { - Town town = universe.getTown(rs.getString("name")); - - if (town == null) { - TownyMessaging.sendErrorMsg("SQL: Load Town " + rs.getString("name") + ". Town was not registered properly on load!"); - return false; - } - - name = town.getName(); - - TownyMessaging.sendDebugMsg("Loading town " + name); - - try { - final UUID mayorUUID = JavaUtil.parseUUIDOrNull(rs.getString("mayor")); - Resident res = mayorUUID != null ? universe.getResident(mayorUUID) : universe.getResident(rs.getString("mayor")); - - if (res == null) - throw new TownyException(); - - town.forceSetMayor(res); - } catch (TownyException e1) { - e1.getMessage(); - if (town.getResidents().size() == 0) { - deleteTown(town); - return true; - } else { - town.findNewMayor(); - } - } - - town.setBoard(rs.getString("townBoard")); - line = rs.getString("tag"); - if (line != null) - town.setTag(line); - line = rs.getString("founder"); - if (line != null) - town.setFounder(line); - town.setPermissions(rs.getString("protectionStatus").replaceAll("#", ",")); - town.setBonusBlocks(rs.getInt("bonus")); - town.setManualTownLevel(rs.getInt("manualTownLevel")); - town.setTaxPercentage(rs.getBoolean("taxpercent")); - town.setTaxes(rs.getFloat("taxes")); - town.setMaxPercentTaxAmount(rs.getFloat("maxPercentTaxAmount")); - town.setHasUpkeep(rs.getBoolean("hasUpkeep")); - town.setHasUnlimitedClaims(rs.getBoolean("hasUnlimitedClaims")); - town.setVisibleOnTopLists(rs.getBoolean("visibleOnTopLists")); - town.setPlotPrice(rs.getFloat("plotPrice")); - town.setPlotTax(rs.getFloat("plotTax")); - town.setEmbassyPlotPrice(rs.getFloat("embassyPlotPrice")); - town.setEmbassyPlotTax(rs.getFloat("embassyPlotTax")); - town.setCommercialPlotPrice(rs.getFloat("commercialPlotPrice")); - town.setCommercialPlotTax(rs.getFloat("commercialPlotTax")); - town.setSpawnCost(rs.getFloat("spawnCost")); - town.setOpen(rs.getBoolean("open")); - town.setPublic(rs.getBoolean("public")); - town.setConquered(rs.getBoolean("conquered"), false); - town.setAdminDisabledPVP(rs.getBoolean("admindisabledpvp")); - town.setAdminEnabledPVP(rs.getBoolean("adminenabledpvp")); - town.setAdminEnabledMobs(rs.getBoolean("adminEnabledMobs")); - town.setAllowedToWar(rs.getBoolean("allowedToWar")); - town.setJoinedNationAt(rs.getLong("joinedNationAt")); - town.setMovedHomeBlockAt(rs.getLong("movedHomeBlockAt")); - town.setForSale(rs.getBoolean("forSale")); - town.setForSalePrice(rs.getDouble("forSalePrice")); - town.setForSaleTime(rs.getLong("forSaleTime")); - town.setPurchasedBlocks(rs.getInt("purchased")); - town.setNationZoneOverride(rs.getInt("nationZoneOverride")); - town.setNationZoneEnabled(rs.getBoolean("nationZoneEnabled")); - - line = rs.getString("maxPercentTaxAmount"); - if (line != null) - town.setMaxPercentTaxAmount(Double.parseDouble(line)); - else - town.setMaxPercentTaxAmount(TownySettings.getMaxTownTaxPercentAmount()); - - line = rs.getString("homeBlock"); - if (line != null) { - search = (line.contains("#")) ? "#" : ","; - tokens = line.split(search); - if (tokens.length == 3) { - TownyWorld world = universe.getWorld(tokens[0]); - if (world == null) - TownyMessaging.sendErrorMsg("[Warning] " + town.getName() + " homeBlock tried to load invalid world."); - else { - try { - int x = Integer.parseInt(tokens[1]); - int z = Integer.parseInt(tokens[2]); - TownBlock homeBlock = universe - .getTownBlock(new WorldCoord(world.getName(), x, z)); - town.forceSetHomeBlock(homeBlock); - } catch (NumberFormatException e) { - TownyMessaging.sendErrorMsg( - "[Warning] " + town.getName() + " homeBlock tried to load invalid location."); - } catch (NotRegisteredException e) { - TownyMessaging.sendErrorMsg( - "[Warning] " + town.getName() + " homeBlock tried to load invalid TownBlock."); - } catch (TownyException e) { - TownyMessaging.sendErrorMsg("[Warning] " + town.getName() + " does not have a home block."); - } - } - } - } - - line = rs.getString("spawn"); - if (line != null) { - search = (line.contains("#")) ? "#" : ","; - tokens = line.split(search); - if (tokens.length >= 4) - try { - town.spawnPosition(Position.deserialize(tokens)); - } catch (IllegalArgumentException e) { - plugin.getLogger().warning("Failed to load spawn location for town " + town.getName() + ": " + e.getMessage()); - } - } - // Load outpost spawns - line = rs.getString("outpostSpawns"); - if (line != null) { - String[] outposts = line.split(";"); - for (String spawn : outposts) { - search = (line.contains("#")) ? "#" : ","; - tokens = spawn.split(search); - if (tokens.length >= 4) - try { - town.forceAddOutpostSpawn(Position.deserialize(tokens)); - } catch (IllegalArgumentException e) { - plugin.getLogger().warning("Failed to load an outpost spawn location for town " + town.getName() + ": " + e.getMessage()); - } - } - } - // Load legacy jail spawns into new Jail objects. - try { - line = rs.getString("jailSpawns"); - } catch (SQLException e) { - // The jailSpawns column no longer exists - line = null; - } - if (line != null) { - String[] jails = line.split(";"); - for (String spawn : jails) { - search = (line.contains("#")) ? "#" : ","; - tokens = spawn.split(search); - if (tokens.length >= 4) - try { - Position pos = Position.deserialize(tokens); - - TownBlock tb = universe.getTownBlock(pos.worldCoord()); - if (tb == null) - continue; - - Jail jail = new Jail(UUID.randomUUID(), town, tb, Collections.singleton(pos)); - universe.registerJail(jail); - town.addJail(jail); - tb.setJail(jail); - jail.save(); - } catch (IllegalArgumentException e) { - plugin.getLogger().warning("Failed to load a legacy jail spawn location for town " + town.getName() + ": " + e.getMessage()); - } - } - } - line = rs.getString("outlaws"); - if (line != null) { - search = (line.contains("#")) ? "#" : ","; - tokens = line.split(search); - - final UUID[] outlawUUIDs = toUUIDArray(tokens); - final List outlaws = outlawUUIDs.length > 0 ? api.getResidents(outlawUUIDs) : api.getResidents(tokens); - - for (Resident outlaw : outlaws) { - town.addOutlaw(outlaw); - } - } - - int conqueredDays = rs.getInt("conqueredDays"); - town.setConqueredDays(conqueredDays); - - try { - long registered = rs.getLong("registered"); - town.setRegistered(registered); - } catch (Exception ignored) { - town.setRegistered(0); - } - - try { - line = rs.getString("metadata"); - if (line != null && !line.isEmpty()) { - MetadataLoader.getInstance().deserializeMetadata(town, line); - } - } catch (SQLException ignored) { - } - - try { - line = rs.getString("nation"); - if (line != null && !line.isEmpty()) { - final UUID nationUUID = JavaUtil.parseUUIDOrNull(line); - Nation nation = nationUUID != null ? universe.getNation(nationUUID) : universe.getNation(line); - // Only set nation if it exists - if (nation != null) - town.setNation(nation, false); - } - } catch (SQLException ignored) { - } - - town.setRuined(rs.getBoolean("ruined")); - town.setRuinedTime(rs.getLong("ruinedTime")); - town.setNeutral(rs.getBoolean("neutral")); - - town.setDebtBalance(rs.getFloat("debtBalance")); - - line = rs.getString("primaryJail"); - if (line != null && !line.isEmpty()) { - UUID uuid = UUID.fromString(line); - if (universe.hasJail(uuid)) - town.setPrimaryJail(universe.getJail(uuid)); - } - - line = rs.getString("trustedResidents"); - if (line != null && !line.isEmpty()) { - search = (line.contains("#")) ? "#" : ","; - for (Resident resident : TownyAPI.getInstance().getResidents(toUUIDArray(line.split(search)))) - town.addTrustedResident(resident); - } - - line = rs.getString("trustedTowns"); - if (line != null && !line.isEmpty()) { - search = (line.contains("#")) ? "#" : ","; - List uuids = Arrays.stream(line.split(search)) - .map(UUID::fromString) - .collect(Collectors.toList()); - town.loadTrustedTowns(TownyAPI.getInstance().getTowns(uuids)); - } - - line = rs.getString("mapColorHexCode"); - if (line != null) - town.setMapColorHexCode(line); - else - town.setMapColorHexCode(MapUtil.generateRandomTownColourAsHexCode()); - - line = rs.getString("allies"); - if (line != null && !line.isEmpty()) { - search = (line.contains("#")) ? "#" : ","; - List uuids = Arrays.stream(line.split(search)) - .map(uuid -> UUID.fromString(uuid)) - .collect(Collectors.toList()); - town.loadAllies(TownyAPI.getInstance().getTowns(uuids)); - } - - line = rs.getString("enemies"); - if (line != null && !line.isEmpty()) { - search = (line.contains("#")) ? "#" : ","; - List uuids = Arrays.stream(line.split(search)) - .map(uuid -> UUID.fromString(uuid)) - .collect(Collectors.toList()); - town.loadEnemies(TownyAPI.getInstance().getTowns(uuids)); - } - - line = rs.getString("visibleOnTopLists"); - if (line != null && !line.isEmpty()) - town.setVisibleOnTopLists(rs.getBoolean("visibleOnTopLists")); - - line = rs.getString("hasActiveWar"); - if (line != null && !line.isEmpty()) - town.setActiveWar(rs.getBoolean("hasActiveWar")); - - return true; - } catch (SQLException e) { - TownyMessaging.sendErrorMsg("SQL: Load Town " + name + " sql Error - " + e.getMessage()); - } catch (Exception e) { - plugin.getLogger().log(Level.WARNING, "SQL: Load Town " + name + " unknown Error - ", e); - } - - return false; - } - - @Override - public boolean loadNations() { - try (Connection connection = getConnection(); - Statement s = connection.createStatement(); - ResultSet rs = s.executeQuery("SELECT * FROM " + tb_prefix + "NATIONS")) { - - while (rs.next()) { - String nationName; - try { - nationName = rs.getString("name"); - } catch (SQLException ex) { - plugin.getLogger().log(Level.SEVERE, "Loading Error: Error fetching a nation name from SQL Database. Skipping loading nation..", ex); - continue; - } - Nation nation = universe.getNation(nationName); - if (nation == null) { - plugin.getLogger().severe(String.format("Loading Error: Could not fetch nation '%s' from Towny universe while loading from SQL DB.", nationName)); - continue; - } - - if (!loadNation(rs)) { - plugin.getLogger().warning("Loading Error: Could not properly read nation data."); - return false; - } - } - } catch (SQLException e) { - TownyMessaging.sendErrorMsg("SQL: Load Nation sql error " + e.getMessage()); - return false; - } - return true; - } - - @Override - public boolean loadNation(Nation nation) { - - /* - * Never called in SQL setups. - */ - return true; - - } - - private boolean loadNation(ResultSet rs) { - String line; - String[] tokens; - String search; - String name = null; - try { - Nation nation = universe.getNation(rs.getString("name")); - - // Could not find nation in universe maps - if (nation == null) { - plugin.getLogger().warning(String.format("Error: The nation with the name '%s' was not registered and cannot be loaded!", rs.getString("name"))); - return false; - } - - name = nation.getName(); - - TownyMessaging.sendDebugMsg("Loading nation " + nation.getName()); - - final UUID capitalUUID = JavaUtil.parseUUIDOrNull(rs.getString("capital")); - Town town = capitalUUID != null ? universe.getTown(capitalUUID) : universe.getTown(rs.getString("capital")); - if (town != null) { - try { - nation.forceSetCapital(town); - } catch (EmptyNationException e1) { - plugin.getLogger().warning("The nation " + nation.getName() + " could not load a capital city and is being disbanded."); - removeNation(nation, DeleteNationEvent.Cause.LOAD); - return true; - } - } - else { - TownyMessaging.sendDebugMsg("Nation " + name + " could not set capital to " + rs.getString("capital") + ", selecting a new capital..."); - if (!nation.findNewCapital()) { - plugin.getLogger().warning("The nation " + nation.getName() + " could not load a capital city and is being disbanded."); - removeNation(nation, DeleteNationEvent.Cause.LOAD); - return true; - } - } - - line = rs.getString("nationBoard"); - if (line != null) - nation.setBoard(rs.getString("nationBoard")); - else - nation.setBoard(""); - - line = rs.getString("mapColorHexCode"); - if (line != null) - nation.setMapColorHexCode(line); - else - nation.setMapColorHexCode(MapUtil.generateRandomNationColourAsHexCode()); - - nation.setTag(rs.getString("tag")); - - line = rs.getString("allies"); - if (line != null) { - search = (line.contains("#")) ? "#" : ","; - - final String[] split = line.split(search); - final UUID[] allyUUIDs = toUUIDArray(split); - - List allies = allyUUIDs.length > 0 ? api.getNations(allyUUIDs) : api.getNations(split); - for (Nation ally : allies) - nation.addAlly(ally); - } - - line = rs.getString("enemies"); - if (line != null) { - search = (line.contains("#")) ? "#" : ","; - - final String[] split = line.split(search); - final UUID[] enemyUUIDs = toUUIDArray(split); - - List enemies = enemyUUIDs.length > 0 ? api.getNations(enemyUUIDs) : api.getNations(split); - for (Nation enemy : enemies) - nation.addEnemy(enemy); - } - - nation.setSpawnCost(rs.getFloat("spawnCost")); - nation.setNeutral(rs.getBoolean("neutral")); - - line = rs.getString("nationSpawn"); - if (line != null) { - search = (line.contains("#")) ? "#" : ","; - tokens = line.split(search); - if (tokens.length >= 4) - try { - nation.spawnPosition(Position.deserialize(tokens)); - } catch (IllegalArgumentException e) { - plugin.getLogger().warning("Failed to load nation spawn location for nation " + nation.getName() + ": " + e.getMessage()); - } - } - - nation.setPublic(rs.getBoolean("isPublic")); - - nation.setOpen(rs.getBoolean("isOpen")); - - nation.setTaxPercentage(rs.getBoolean("taxpercent")); - nation.setTaxes(rs.getDouble("taxes")); - - line = rs.getString("maxPercentTaxAmount"); - if (line != null) - nation.setMaxPercentTaxAmount(Double.parseDouble(line)); - else - nation.setMaxPercentTaxAmount(TownySettings.getMaxNationTaxPercentAmount()); - - try { - line = rs.getString("registered"); - if (line != null) { - nation.setRegistered(Long.parseLong(line)); - } else { - nation.setRegistered(0); - } - } catch (SQLException ignored) { - } catch (NumberFormatException | NullPointerException e) { - nation.setRegistered(0); - } - - try { - line = rs.getString("metadata"); - if (line != null && !line.isEmpty()) { - MetadataLoader.getInstance().deserializeMetadata(nation, line); - } - } catch (SQLException ignored) { - } - - try { - line = rs.getString("conqueredTax"); - if (line != null && !line.isEmpty()) { - nation.setConqueredTax(Double.parseDouble(line)); - } - } catch (SQLException ignored) { - } - - line = rs.getString("sanctionedTowns"); - if (line != null) { - nation.loadSanctionedTowns(line.split("#")); - } - - line = rs.getString("hasActiveWar"); - if (line != null && !line.isEmpty()) - nation.setActiveWar(rs.getBoolean("hasActiveWar")); - - - nation.setManualNationLevel(rs.getInt("manualNationLevel")); - - return true; - } catch (SQLException e) { - TownyMessaging.sendErrorMsg("SQL: Load Nation " + name + " SQL Error - " + e.getMessage()); - } - - return false; - } - - @Override - public boolean loadWorlds() { - try (Connection connection = getConnection(); - Statement s = connection.createStatement(); - ResultSet rs = s.executeQuery("SELECT * FROM " + tb_prefix + "WORLDS")) { - - while (rs.next()) { - String worldName; - try { - worldName = rs.getString("name"); - } catch (SQLException ex) { - plugin.getLogger().log(Level.SEVERE, "Loading Error: Error fetching a world name from SQL Database. Skipping loading world..", ex); - continue; - } - TownyWorld world = universe.getWorld(worldName); - if (world == null) { - plugin.getLogger().severe(String.format("Loading Error: Could not fetch world '%s' from Towny universe while loading from SQL DB.", worldName)); - continue; - } - if (!loadWorld(rs)) { - plugin.getLogger().warning("Loading Error: Could not read properly world data."); - return false; - } - } - } catch (SQLException e) { - TownyMessaging.sendErrorMsg("SQL: Error reading worlds from SQL database!"); - return false; - } - return true; - } - - @Override - public boolean loadWorld(TownyWorld world) { - try (Connection connection = getConnection(); - PreparedStatement ps = connection.prepareStatement("SELECT * FROM " + tb_prefix + "WORLDS WHERE name=?")) { - ps.setString(1, world.getName()); - - try (ResultSet rs = ps.executeQuery()) { - if (rs.next()) { - return loadWorld(rs); - } - } - } catch (SQLException e) { - TownyMessaging.sendErrorMsg("SQL: Load world sql error (" + world.getName() + ")" + e.getMessage()); - } - return false; - } - - private boolean loadWorld(ResultSet rs) { - String line; - boolean result; - long resultLong; - String search; - String worldName = null; - try { - worldName = rs.getString("name"); - TownyWorld world = universe.getWorld(worldName); - if (world == null) - throw new Exception("World " + worldName + " not registered!"); - - TownyMessaging.sendDebugMsg("Loading world " + world.getName()); - - line = rs.getString("uuid"); - if (line != null && !line.isEmpty()) { - try { - world.setUUID(UUID.fromString(line)); - } catch (IllegalArgumentException ignored) { - UUID uuid = BukkitTools.getWorldUUID(worldName); - if (uuid != null) - world.setUUID(uuid); - } - } else { - UUID uuid = BukkitTools.getWorldUUID(worldName); - if (uuid != null) - world.setUUID(uuid); - } - - result = rs.getBoolean("claimable"); - try { - world.setClaimable(result); - } catch (Exception ignored) { - } - - result = rs.getBoolean("pvp"); - try { - world.setPVP(result); - } catch (Exception ignored) { - } - - result = rs.getBoolean("forcepvp"); - try { - world.setForcePVP(result); - } catch (Exception ignored) { - } - - result = rs.getBoolean("friendlyFire"); - try { - world.setFriendlyFire(result); - } catch (Exception ignored) { - } - - result = rs.getBoolean("forcetownmobs"); - try { - world.setForceTownMobs(result); - } catch (Exception ignored) { - } - - result = rs.getBoolean("wildernessmobs"); - try { - world.setWildernessMobs(result); - } catch (Exception ignored) { - } - - result = rs.getBoolean("worldmobs"); - try { - world.setWorldMobs(result); - } catch (Exception ignored) { - } - - result = rs.getBoolean("firespread"); - try { - world.setFire(result); - } catch (Exception ignored) { - } - - result = rs.getBoolean("forcefirespread"); - try { - world.setForceFire(result); - } catch (Exception ignored) { - } - - result = rs.getBoolean("explosions"); - try { - world.setExpl(result); - } catch (Exception ignored) { - } - - result = rs.getBoolean("forceexplosions"); - try { - world.setForceExpl(result); - } catch (Exception ignored) { - } - - result = rs.getBoolean("endermanprotect"); - try { - world.setEndermanProtect(result); - } catch (Exception ignored) { - } - - result = rs.getBoolean("disablecreaturetrample"); - try { - world.setDisableCreatureTrample(result); - } catch (Exception ignored) { - } - - result = rs.getBoolean("unclaimedZoneBuild"); - try { - world.setUnclaimedZoneBuild(result); - } catch (Exception ignored) { - } - - result = rs.getBoolean("unclaimedZoneDestroy"); - try { - world.setUnclaimedZoneDestroy(result); - } catch (Exception ignored) { - } - - result = rs.getBoolean("unclaimedZoneSwitch"); - try { - world.setUnclaimedZoneSwitch(result); - } catch (Exception ignored) { - } - - result = rs.getBoolean("unclaimedZoneItemUse"); - try { - world.setUnclaimedZoneItemUse(result); - } catch (Exception ignored) { - } - - line = rs.getString("unclaimedZoneName"); - try { - world.setUnclaimedZoneName(line); - } catch (Exception ignored) { - } - - line = rs.getString("unclaimedZoneIgnoreIds"); - if (line != null) - try { - List mats = new ArrayList<>(); - search = (line.contains("#")) ? "#" : ","; - for (String split : line.split(search)) - if (!split.isEmpty()) - mats.add(split); - - world.setUnclaimedZoneIgnore(mats); - } catch (Exception ignored) { - } - - result = rs.getBoolean("isDeletingEntitiesOnUnclaim"); - try { - world.setDeletingEntitiesOnUnclaim(result); - } catch (Exception ignored) { - } - - line = rs.getString("unclaimDeleteEntityTypes"); - if (line != null) - try { - List entityTypes = new ArrayList<>(); - search = (line.contains("#")) ? "#" : ","; - for (String split : line.split(search)) - if (!split.isEmpty()) - entityTypes.add(split); - - world.setUnclaimDeleteEntityTypes(entityTypes); - } catch (Exception ignored) { - } - - result = rs.getBoolean("usingPlotManagementDelete"); - try { - world.setUsingPlotManagementDelete(result); - } catch (Exception ignored) { - } - - line = rs.getString("plotManagementDeleteIds"); - if (line != null) - try { - List mats = new ArrayList<>(); - search = (line.contains("#")) ? "#" : ","; - for (String split : line.split(search)) - if (!split.isEmpty()) - mats.add(split); - - world.setPlotManagementDeleteIds(mats); - } catch (Exception ignored) { - } - - result = rs.getBoolean("usingPlotManagementMayorDelete"); - try { - world.setUsingPlotManagementMayorDelete(result); - } catch (Exception ignored) { - } - - line = rs.getString("plotManagementMayorDelete"); - if (line != null) - try { - List materials = new ArrayList<>(); - search = (line.contains("#")) ? "#" : ","; - for (String split : line.split(search)) - if (!split.isEmpty()) - try { - materials.add(split.toUpperCase().trim()); - } catch (NumberFormatException ignored) { - } - world.setPlotManagementMayorDelete(materials); - } catch (Exception ignored) { - } - - result = rs.getBoolean("usingPlotManagementRevert"); - try { - world.setUsingPlotManagementRevert(result); - } catch (Exception ignored) { - } - - line = rs.getString("plotManagementIgnoreIds"); - if (line != null) - try { - List mats = new ArrayList<>(); - search = (line.contains("#")) ? "#" : ","; - for (String split : line.split(search)) - if (!split.isEmpty()) - mats.add(split); - - world.setPlotManagementIgnoreIds(mats); - } catch (Exception ignored) { - } - - result = rs.getBoolean("usingPlotManagementWildRegen"); - try { - world.setUsingPlotManagementWildEntityRevert(result); - } catch (Exception ignored) { - } - - line = rs.getString("revertOnUnclaimWhitelistMaterials"); - if (line != null) - try { - List materials = new ArrayList<>(); - for (String split : line.split("#")) - if (!split.isEmpty()) - try { - materials.add(split.trim()); - } catch (NumberFormatException ignored) { - } - world.setRevertOnUnclaimWhitelistMaterials(materials); - } catch (Exception ignored) { - } - - line = rs.getString("plotManagementWildRegenEntities"); - if (line != null) - try { - List entities = new ArrayList<>(); - search = (line.contains("#")) ? "#" : ","; - for (String split : line.split(search)) - if (!split.isEmpty()) - try { - entities.add(split.trim()); - } catch (NumberFormatException ignored) { - } - world.setPlotManagementWildRevertEntities(entities); - } catch (Exception ignored) { - } - - line = rs.getString("plotManagementWildRegenBlockWhitelist"); - if (line != null) - try { - List materials = new ArrayList<>(); - search = (line.contains("#")) ? "#" : ","; - for (String split : line.split(search)) - if (!split.isEmpty()) - try { - materials.add(split.trim()); - } catch (NumberFormatException ignored) { - } - world.setPlotManagementWildRevertBlockWhitelist(materials); - } catch (Exception ignored) { - } - - line = rs.getString("wildRegenBlocksToNotOverwrite"); - if (line != null) - try { - List materials = new ArrayList<>(); - search = (line.contains("#")) ? "#" : ","; - for (String split : line.split(search)) - if (!split.isEmpty()) - try { - materials.add(split.trim()); - } catch (NumberFormatException ignored) { - } - world.setWildRevertMaterialsToNotOverwrite(materials); - } catch (Exception ignored) { - } - - resultLong = rs.getLong("plotManagementWildRegenSpeed"); - try { - world.setPlotManagementWildRevertDelay(resultLong); - } catch (Exception ignored) { - } - - result = rs.getBoolean("usingPlotManagementWildRegenBlocks"); - try { - world.setUsingPlotManagementWildBlockRevert(result); - } catch (Exception ignored) { - } - - line = rs.getString("plotManagementWildRegenBlocks"); - if (line != null) - try { - List materials = new ArrayList<>(); - search = (line.contains("#")) ? "#" : ","; - for (String split : line.split(search)) - if (!split.isEmpty()) - try { - materials.add(split.trim()); - } catch (NumberFormatException ignored) { - } - world.setPlotManagementWildRevertMaterials(materials); - } catch (Exception ignored) { - } - - result = rs.getBoolean("usingTowny"); - try { - world.setUsingTowny(result); - } catch (Exception ignored) { - } - - result = rs.getBoolean("warAllowed"); - try { - world.setWarAllowed(result); - } catch (Exception ignored) { - } - - result = rs.getBoolean("jailing"); - try { - world.setJailingEnabled(result); - } catch (Exception ignored) { - } - - try { - line = rs.getString("metadata"); - if (line != null && !line.isEmpty()) { - MetadataLoader.getInstance().deserializeMetadata(world, line); - } - } catch (SQLException ignored) { - } - return true; - } catch (SQLException e) { - TownyMessaging.sendErrorMsg( - "SQL: Load world sql error (" + (worldName != null ? worldName : "NULL") + ")" + e.getMessage()); - } catch (Exception e) { - TownyMessaging.sendErrorMsg(e.getMessage()); - } - return false; - } - - @Override - public boolean loadTownBlocks() { - - String line = ""; - boolean result; - TownyMessaging.sendDebugMsg("Loading Town Blocks."); - - TownBlock townBlock = null; - try (Connection connection = getConnection(); - Statement s = connection.createStatement(); - ResultSet rs = s.executeQuery("SELECT * FROM " + tb_prefix + "TOWNBLOCKS")) { - - while (rs.next()) { - String worldName = rs.getString("world"); - int x = rs.getInt("x"); - int z = rs.getInt("z"); - - if (!universe.hasTownyWorld(worldName)) - continue; - - try { - townBlock = universe.getTownBlock(new WorldCoord(worldName, x, z)); - } catch (NotRegisteredException ex) { - TownyMessaging.sendErrorMsg("Loading Error: Exception while fetching townblock: " + worldName + " " - + x + " " + z + " from memory!"); - return false; - } - - line = rs.getString("name"); - if (line != null) - try { - townBlock.setName(line.trim()); - } catch (Exception ignored) { - } - - line = rs.getString("town"); - if (line != null) { - line = line.trim(); - - final UUID townUUID = JavaUtil.parseUUIDOrNull(line); - Town town = townUUID != null ? universe.getTown(townUUID) : universe.getTown(line); - - if (town == null) { - TownyMessaging.sendErrorMsg("TownBlock file contains unregistered Town: " + line - + ", deleting " + townBlock.getWorld().getName() + "," + townBlock.getX() + "," - + townBlock.getZ()); - universe.removeTownBlock(townBlock); - deleteTownBlock(townBlock); - continue; - } - - townBlock.setTown(town, false); - try { - town.addTownBlock(townBlock); - TownyWorld townyWorld = townBlock.getWorld(); - if (townyWorld != null && !townyWorld.hasTown(town)) - townyWorld.addTown(town); - } catch (AlreadyRegisteredException ignored) { - } - } - - line = rs.getString("resident"); - if (line != null && !(line = line.trim()).isEmpty()) { - final UUID residentUUID = JavaUtil.parseUUIDOrNull(line); - Resident res = residentUUID != null ? universe.getResident(residentUUID) : universe.getResident(line); - if (res != null) { - townBlock.setResident(res, false); - } else { - TownyMessaging.sendErrorMsg(String.format("Error fetching resident '%s' for townblock '%s'!", line, townBlock.toString())); - } - } - - line = rs.getString("type"); - if (line != null) - townBlock.setType(TownBlockTypeHandler.getTypeInternal(line)); - - line = rs.getString("price"); - if (line != null) - try { - townBlock.setPlotPrice(Float.parseFloat(line.trim())); - } catch (Exception ignored) { - } - - boolean taxed = rs.getBoolean("taxed"); - try { - townBlock.setTaxed(taxed); - } catch (Exception ignored) { - } - - line = rs.getString("typeName"); - if (line != null) - townBlock.setType(TownBlockTypeHandler.getTypeInternal(line)); - - boolean outpost = rs.getBoolean("outpost"); - try { - townBlock.setOutpost(outpost); - } catch (Exception ignored) { - } - - line = rs.getString("permissions"); - if ((line != null) && !line.isEmpty()) - try { - townBlock.setPermissions(line.trim().replaceAll("#", ",")); - // set = true; - } catch (Exception ignored) { - } - - result = rs.getBoolean("changed"); - try { - townBlock.setChanged(result); - } catch (Exception ignored) { - } - - townBlock.setClaimedAt(rs.getLong("claimedAt")); - - - line = rs.getString("minTownMembershipDays"); - if (line != null && !line.isEmpty()) - townBlock.setMinTownMembershipDays(Integer.valueOf(line)); - - line = rs.getString("maxTownMembershipDays"); - if (line != null && !line.isEmpty()) - townBlock.setMaxTownMembershipDays(Integer.valueOf(line)); - - try { - line = rs.getString("metadata"); - if (line != null && !line.isEmpty()) { - MetadataLoader.getInstance().deserializeMetadata(townBlock, line); - } - } catch (SQLException ignored) { - } - - try { - line = rs.getString("groupID"); - if (line != null && !line.isEmpty()) { - try { - UUID groupID = UUID.fromString(line.trim()); - PlotGroup group = universe.getGroup(groupID); - if (group != null) { - townBlock.setPlotObjectGroup(group); - if (group.getPermissions() == null && townBlock.getPermissions() != null) - group.setPermissions(townBlock.getPermissions()); - if (townBlock.hasResident()) - group.setResident(townBlock.getResidentOrNull()); - } - } catch (Exception ignored) { - } - - } - } catch (SQLException ignored) { - } - - try { - line = rs.getString("districtID"); - if (line != null && !line.isEmpty()) { - try { - UUID districtID = UUID.fromString(line.trim()); - District district = universe.getDistrict(districtID); - if (district != null) { - townBlock.setDistrict(district); - } - } catch (Exception ignored) { - } - - } - } catch (SQLException ignored) { - } - - line = rs.getString("trustedResidents"); - if (line != null && !line.isEmpty()) { - String search = (line.contains("#")) ? "#" : ","; - for (Resident resident : TownyAPI.getInstance().getResidents(toUUIDArray(line.split(search)))) - townBlock.addTrustedResident(resident); - - if (townBlock.hasPlotObjectGroup() && townBlock.getPlotObjectGroup().getTrustedResidents().isEmpty() && townBlock.hasTrustedResidents()) { - townBlock.getPlotObjectGroup().setTrustedResidents(townBlock.getTrustedResidents()); - } - } - - line = rs.getString("customPermissionData"); - if (line != null && !line.isEmpty()) { - Map map = new Gson().fromJson(line, new TypeToken>(){}.getType()); - - for (Map.Entry entry : map.entrySet()) { - Resident resident; - try { - resident = TownyAPI.getInstance().getResident(UUID.fromString(entry.getKey())); - } catch (IllegalArgumentException e) { - continue; - } - - if (resident == null) - continue; - - townBlock.getPermissionOverrides().put(resident, new PermissionData(entry.getValue())); - } - - if (townBlock.hasPlotObjectGroup() && townBlock.getPlotObjectGroup().getPermissionOverrides().isEmpty() && townBlock.hasPermissionOverrides()) { - townBlock.getPlotObjectGroup().setPermissionOverrides(townBlock.getPermissionOverrides()); - } - } - } + /* + * Load individual towny object + */ - } catch (SQLException ex) { - plugin.getLogger().log(Level.WARNING, "Loading Error: Exception while reading TownBlock: " - + (townBlock != null ? townBlock : "NULL") + " at line: " + line + " in the sql database", ex); - return false; - } + @Override + public boolean loadJailUUIDs(Set uuids) throws ObjectCouldNotBeLoadedException { + return loadResultSetOfType(TownyDBTableType.JAIL, uuids); + } + + @Override + public boolean loadPlotGroupUUIDs(Set uuids) throws ObjectCouldNotBeLoadedException { + return loadResultSetOfType(TownyDBTableType.PLOTGROUP, uuids); + } - return true; + @Override + public boolean loadDistrictUUIDs(Set uuids) throws ObjectCouldNotBeLoadedException { + return loadResultSetOfType(TownyDBTableType.DISTRICT, uuids); } @Override - public boolean loadPlotGroups() { - TownyMessaging.sendDebugMsg("Loading plot groups."); - - try (Connection connection = getConnection(); - Statement s = connection.createStatement(); - ResultSet rs = s.executeQuery("SELECT * FROM " + tb_prefix + "PLOTGROUPS ")) { - while (rs.next()) { - if (!loadPlotGroup(rs)) { - plugin.getLogger().warning("Loading Error: Could not read plotgroup data properly."); - return false; - } - } - } catch (SQLException e) { - TownyMessaging.sendErrorMsg("SQL: Load PlotGroup sql Error - " + e.getMessage()); - return false; - } + public boolean loadResidentUUIDs(Set uuids) throws ObjectCouldNotBeLoadedException { + return loadResultSetOfType(TownyDBTableType.RESIDENT, uuids); + } + + @Override + public boolean loadTownUUIDs(Set uuids) throws ObjectCouldNotBeLoadedException { + return loadResultSetOfType(TownyDBTableType.TOWN, uuids); + } + + @Override + public boolean loadNationUUIDs(Set uuids) throws ObjectCouldNotBeLoadedException { + return loadResultSetOfType(TownyDBTableType.NATION, uuids); + } + + @Override + public boolean loadWorldUUIDs(Set uuids) throws ObjectCouldNotBeLoadedException { + return loadResultSetOfType(TownyDBTableType.WORLD, uuids); + } + public boolean loadTownBlocks(Collection townBlocks) throws ObjectCouldNotBeLoadedException { + for (TownBlock townblock : townBlocks) + if (!loadTownBlock(townblock)) + throw new ObjectCouldNotBeLoadedException("Loading Error: Could not read the townblock with details: '" + townblock.toString() + "' from the TOWNBLOCKS table."); return true; } + /* + * Methods that return objects as Maps for loading. + */ + @Override - public boolean loadDistricts() { - TownyMessaging.sendDebugMsg("Loading districts."); - - try (Connection connection = getConnection(); - Statement s = connection.createStatement(); - ResultSet rs = s.executeQuery("SELECT * FROM " + tb_prefix + "DISTRICTS ")) { - while (rs.next()) { - if (!loadDistrict(rs)) { - plugin.getLogger().warning("Loading Error: Could not read district data properly."); - return false; - } - } + public Map getJailMap(UUID uuid) { + if (!isReady()) + return null; + try (Statement s = getConnection().createStatement(); + ResultSet rs = s.executeQuery("SELECT uuid FROM " + tb_prefix + "JAILS WHERE uuid='" + uuid + "'")) { + return loadResultSetIntoMap(rs); } catch (SQLException e) { - TownyMessaging.sendErrorMsg("SQL: Load District sql Error - " + e.getMessage()); - return false; + TownyMessaging.sendErrorMsg("SQL: Unable to find jail with UUID " + uuid.toString() + " in the database!"); + return null; } - - return true; } @Override - public boolean loadCooldowns() { - try (Connection connection = getConnection(); - PreparedStatement statement = connection.prepareStatement("SELECT * FROM " + tb_prefix + TownyDBTableType.COOLDOWN.tableName()); - ResultSet resultSet = statement.executeQuery()) { - - while (resultSet.next()) - CooldownTimerTask.getCooldowns().put(resultSet.getString("key"), resultSet.getLong("expiry")); + public Map getPlotGroupMap(UUID uuid) { + if (!isReady()) + return null; + try (Statement s = getConnection().createStatement(); + ResultSet rs = s.executeQuery("SELECT groupID FROM " + tb_prefix + "PLOTGROUPS WHERE groupID='" + uuid + "'")) { + return loadResultSetIntoMap(rs); } catch (SQLException e) { - plugin.getLogger().log(Level.WARNING, "An exception occurred when loading cooldowns", e); - return false; + TownyMessaging.sendErrorMsg("SQL: Unable to find plotgroup with UUID " + uuid.toString() + " in the database!"); + return null; } - - return true; } @Override - public boolean saveCooldowns() { - for (Map.Entry entry : CooldownTimerTask.getCooldowns().entrySet()) { - final Map data = new HashMap<>(); - data.put("key", entry.getKey()); - data.put("expiry", entry.getValue()); - - queueUpdateDB(TownyDBTableType.COOLDOWN.tableName(), data, Collections.singletonList("key")); + public Map getDistrictMap(UUID uuid) { + if (!isReady()) + return null; + try (Statement s = getConnection().createStatement(); + ResultSet rs = s.executeQuery("SELECT uuid FROM " + tb_prefix + "DISTRICTS WHERE uuid='" + uuid + "'")) { + return loadResultSetIntoMap(rs); + } catch (SQLException e) { + TownyMessaging.sendErrorMsg("SQL: Unable to find district with UUID " + uuid.toString() + " in the database!"); + return null; } - - return true; } - private boolean loadPlotGroup(ResultSet rs) { - String line = null; - String uuid = null; - - try { - PlotGroup group = universe.getGroup(UUID.fromString(rs.getString("groupID"))); - if (group == null) { - TownyMessaging.sendErrorMsg("SQL: A plot group was not registered properly on load!"); - return true; - } - uuid = group.getUUID().toString(); - - line = rs.getString("groupName"); - if (line != null) - try { - group.setName(line.trim()); - } catch (Exception ignored) { - } - - line = rs.getString("town"); - if (line != null) { - final UUID townUUID = JavaUtil.parseUUIDOrNull(line); - Town town = townUUID != null ? universe.getTown(townUUID) : universe.getTown(line.trim()); - if (town != null) { - group.setTown(town); - } else { - deletePlotGroup(group); - return true; - } - } - - line = rs.getString("groupPrice"); - if (line != null) { - try { - group.setPrice(Float.parseFloat(line.trim())); - } catch (Exception ignored) {} - } - - line = rs.getString("metadata"); - if (line != null) { - MetadataLoader.getInstance().deserializeMetadata(group, line); - } + @Override + public Map getResidentMap(UUID uuid) { + if (!isReady()) + return null; + try (Statement s = getConnection().createStatement(); + ResultSet rs = s.executeQuery("SELECT uuid FROM " + tb_prefix + "RESIDENTS WHERE uuid='" + uuid + "'")) { + return loadResultSetIntoMap(rs); } catch (SQLException e) { - plugin.getLogger().log(Level.WARNING, "Loading Error: Exception while reading plot group: " + uuid - + " at line: " + line + " in the sql database", e); - return false; + TownyMessaging.sendErrorMsg("SQL: Unable to find resident with UUID " + uuid.toString() + " in the database!"); + return null; } - return true; } @Override - public boolean loadPlotGroup(PlotGroup group) { - // Unused in SQL. - return true; + public Map getTownMap(UUID uuid) { + if (!isReady()) + return null; + try (Statement s = getConnection().createStatement(); + ResultSet rs = s.executeQuery("SELECT uuid FROM " + tb_prefix + "TOWNS WHERE uuid='" + uuid + "'")) { + return loadResultSetIntoMap(rs); + } catch (SQLException e) { + TownyMessaging.sendErrorMsg("SQL: Unable to find town with UUID " + uuid.toString() + " in the database!"); + return null; + } } - private boolean loadDistrict(ResultSet rs) { - String line = null; - String uuidString = null; - - try { - District district = universe.getDistrict(UUID.fromString(rs.getString("uuid"))); - if (district == null) { - TownyMessaging.sendErrorMsg("SQL: A district was not registered properly on load!"); - return true; - } - uuidString = district.getUUID().toString(); - - line = rs.getString("districtName"); - if (line != null) - try { - district.setName(line.trim()); - } catch (Exception ignored) { - } - - line = rs.getString("town"); - if (line != null) { - UUID uuid = UUID.fromString(line.trim()); - if (uuid == null) { - deleteDistrict(district); - return true; - } - Town town = universe.getTown(uuid); - if (town != null) { - district.setTown(town); - } else { - deleteDistrict(district); - return true; - } - } - - line = rs.getString("metadata"); - if (line != null) { - MetadataLoader.getInstance().deserializeMetadata(district, line); - } + @Override + public Map getNationMap(UUID uuid) { + if (!isReady()) + return null; + try (Statement s = getConnection().createStatement(); + ResultSet rs = s.executeQuery("SELECT uuid FROM " + tb_prefix + "NATIONS WHERE uuid='" + uuid + "'")) { + return loadResultSetIntoMap(rs); } catch (SQLException e) { - plugin.getLogger().log(Level.WARNING, "Loading Error: Exception while reading district: " + uuidString - + " at line: " + line + " in the sql database", e); - return false; + TownyMessaging.sendErrorMsg("SQL: Unable to find nation with UUID " + uuid.toString() + " in the database!"); + return null; } - return true; } - + @Override - public boolean loadDistrict(District district) { - // Unused in SQL. - return true; + public Map getWorldMap(UUID uuid) { + if (!isReady()) + return null; + try (Statement s = getConnection().createStatement(); + ResultSet rs = s.executeQuery("SELECT uuid FROM " + tb_prefix + "WORLDS WHERE uuid='" + uuid + "'")) { + return loadResultSetIntoMap(rs); + } catch (SQLException e) { + TownyMessaging.sendErrorMsg("SQL: Unable to find world with UUID " + uuid.toString() + " in the database!"); + return null; + } } - - @Override - public boolean loadJails() { - TownyMessaging.sendDebugMsg("Loading Jails"); - try (Connection connection = getConnection(); - Statement s = connection.createStatement(); - ResultSet rs = s.executeQuery("SELECT * FROM " + tb_prefix + "JAILS ")) { - while (rs.next()) { - if (!loadJail(rs)) { - plugin.getLogger().warning("Loading Error: Could not read jail data properly."); - return false; - } - } + @Override + public Map getTownBlockMap(TownBlock townBlock) { + if (!isReady()) + return null; + try (Statement s = getConnection().createStatement(); + ResultSet rs = s.executeQuery("SELECT * FROM " + tb_prefix + "TOWNBLOCKS")) { + return loadResultSetIntoMap(rs); } catch (SQLException e) { - TownyMessaging.sendErrorMsg("SQL: Load Jail sql Error - " + e.getMessage()); - return false; + TownyMessaging.sendErrorMsg("Loading Error: Exception while reading TownBlock: " + + (townBlock != null ? townBlock : "NULL") + " in the sql database"); + return null; } - - return true; } - + + /* + * Save individual towny objects + */ + @Override - public boolean loadJail(Jail jail) { - // Unused in SQL. - return true; - } - - private boolean loadJail(ResultSet rs) { - String line; - String[] tokens; - String uuid = null; + public synchronized boolean saveJail(Jail jail, Map data) { + TownyMessaging.sendDebugMsg("Saving jail " + jail.getUUID()); try { - Jail jail = universe.getJail(UUID.fromString(rs.getString("uuid"))); - if (jail == null) { - TownyMessaging.sendErrorMsg("SQL: A jail was not registered properly on load!"); - return true; - } - uuid = jail.getUUID().toString(); - - line = rs.getString("townBlock"); - if (line != null) { - tokens = line.split("#"); - WorldCoord wc = null; - try { - wc = new WorldCoord(tokens[0], Integer.parseInt(tokens[1].trim()), Integer.parseInt(tokens[2].trim())); - if (wc.isWilderness() || wc.getTownOrNull() == null) // Not a number format exception but it gets handled the same so why not. - throw new NumberFormatException(); - } catch (NumberFormatException e) { - TownyMessaging.sendErrorMsg("Jail " + jail.getUUID() + " tried to load invalid townblock " + line + " deleting jail."); - removeJail(jail); - deleteJail(jail); - return true; - } - - TownBlock tb = wc.getTownBlockOrNull(); - Town town = tb.getTownOrNull(); - jail.setTownBlock(tb); - jail.setTown(town); - tb.setJail(jail); - town.addJail(jail); - } - - line = rs.getString("spawns"); - if (line != null) { - String[] jails = line.split(";"); - for (String spawn : jails) { - tokens = spawn.split("#"); - if (tokens.length >= 4) - try { - jail.addJailCell(Position.deserialize(tokens)); - } catch (IllegalArgumentException e) { - TownyMessaging.sendErrorMsg("Jail " + jail.getUUID() + " tried to load invalid spawn " + line + " skipping: " + e.getMessage()); - } - } - if (jail.getJailCellLocations().size() < 1) { - TownyMessaging.sendErrorMsg("Jail " + jail.getUUID() + " loaded with zero spawns " + line + " deleting jail."); - removeJail(jail); - deleteJail(jail); - return true; - } - } - - + updateDB("JAILS", data, Collections.singletonList("uuid")); return true; - } catch (SQLException e) { - TownyMessaging.sendErrorMsg("SQL: Load Jail " + uuid + " sql Error - " + e.getMessage()); } catch (Exception e) { - plugin.getLogger().log(Level.WARNING, "SQL: Load Jail " + uuid + " unknown Error - ", e); + TownyMessaging.sendErrorMsg("SQL: Save jail unknown error"); + e.printStackTrace(); } - return false; } - - /* - * Save individual towny objects - */ @Override - public synchronized boolean saveResident(Resident resident) { - - TownyMessaging.sendDebugMsg("Saving Resident " + resident.getName()); + public synchronized boolean savePlotGroup(PlotGroup group, Map data) { + TownyMessaging.sendDebugMsg("Saving group " + group.getName()); try { - HashMap res_hm = new HashMap<>(); - res_hm.put("name", resident.getName()); - res_hm.put("uuid", resident.hasUUID() ? resident.getUUID().toString() : ""); - res_hm.put("lastOnline", resident.getLastOnline()); - res_hm.put("registered", resident.getRegistered()); - res_hm.put("joinedTownAt", resident.getJoinedTownAt()); - res_hm.put("isNPC", resident.isNPC()); - res_hm.put("jailUUID", resident.isJailed() ? resident.getJail().getUUID() : ""); - res_hm.put("jailCell", resident.getJailCell()); - res_hm.put("jailHours", resident.getJailHours()); - res_hm.put("jailBail", resident.getJailBailCost()); - res_hm.put("title", resident.getTitle()); - res_hm.put("surname", resident.getSurname()); - - if (!TownySettings.getDefaultResidentAbout().equals(resident.getAbout())) - res_hm.put("about", resident.getAbout()); - res_hm.put("town", resident.hasTown() ? resident.getTown().getUUID() : ""); - res_hm.put("town-ranks", resident.hasTown() ? StringMgmt.join(resident.getTownRanksForSaving(), "#") : ""); - res_hm.put("nation-ranks", resident.hasTown() ? StringMgmt.join(resident.getNationRanksForSaving(), "#") : ""); - res_hm.put("friends", StringMgmt.join(toUUIDList(resident.getFriends()), "#")); - res_hm.put("protectionStatus", resident.getPermissions().toString().replaceAll(",", "#")); - - if (resident.hasMeta()) - res_hm.put("metadata", serializeMetadata(resident)); - else - res_hm.put("metadata", ""); - - updateDB("RESIDENTS", res_hm, Collections.singletonList("uuid")); + updateDB("PLOTGROUPS", data, Collections.singletonList("groupID")); return true; - } catch (Exception e) { - TownyMessaging.sendErrorMsg("SQL: Save Resident unknown error " + e.getMessage()); + TownyMessaging.sendErrorMsg("SQL: Save Plot groups unknown error"); + e.printStackTrace(); } return false; } - + @Override - public synchronized boolean saveHibernatedResident(UUID uuid, long registered) { - TownyMessaging.sendDebugMsg("Saving Hibernated Resident " + uuid); + public boolean saveDistrict(District district, Map data) { + TownyMessaging.sendDebugMsg("Saving district " + district.getName()); try { - HashMap res_hm = new HashMap<>(); - res_hm.put("uuid", uuid); - res_hm.put("registered", registered); - - updateDB("HIBERNATEDRESIDENTS", res_hm, Collections.singletonList("uuid")); + updateDB("DISTRICTS", data, Collections.singletonList("uuid")); return true; - } catch (Exception e) { - TownyMessaging.sendErrorMsg("SQL: Save Hibernated Resident unknown error " + e.getMessage()); + TownyMessaging.sendErrorMsg("SQL: Save District unknown error"); + e.printStackTrace(); } return false; } @Override - public synchronized boolean saveTown(Town town) { - - TownyMessaging.sendDebugMsg("Saving town " + town.getName()); + public synchronized boolean saveResident(Resident resident, Map data) { + TownyMessaging.sendDebugMsg("Saving Resident " + resident.getName()); try { - HashMap twn_hm = new HashMap<>(); - twn_hm.put("name", town.getName()); - twn_hm.put("outlaws", StringMgmt.join(toUUIDList(town.getOutlaws()), "#")); - twn_hm.put("mayor", town.hasMayor() ? town.getMayor().getUUID() : ""); - twn_hm.put("nation", town.hasNation() ? town.getNationOrNull().getUUID() : ""); - twn_hm.put("townBoard", town.getBoard()); - twn_hm.put("tag", town.getTag()); - twn_hm.put("founder", town.getFounder()); - twn_hm.put("protectionStatus", town.getPermissions().toString().replaceAll(",", "#")); - twn_hm.put("bonus", town.getBonusBlocks()); - twn_hm.put("manualTownLevel", town.getManualTownLevel()); - twn_hm.put("purchased", town.getPurchasedBlocks()); - twn_hm.put("nationZoneOverride", town.getNationZoneOverride()); - twn_hm.put("nationZoneEnabled", town.isNationZoneEnabled()); - twn_hm.put("commercialPlotPrice", town.getCommercialPlotPrice()); - twn_hm.put("commercialPlotTax", town.getCommercialPlotTax()); - twn_hm.put("embassyPlotPrice", town.getEmbassyPlotPrice()); - twn_hm.put("embassyPlotTax", town.getEmbassyPlotTax()); - twn_hm.put("spawnCost", town.getSpawnCost()); - twn_hm.put("plotPrice", town.getPlotPrice()); - twn_hm.put("plotTax", town.getPlotTax()); - twn_hm.put("taxes", town.getTaxes()); - twn_hm.put("hasUpkeep", town.hasUpkeep()); - twn_hm.put("hasUnlimitedClaims", town.hasUnlimitedClaims()); - twn_hm.put("visibleOnTopLists", town.isVisibleOnTopLists()); - twn_hm.put("taxpercent", town.isTaxPercentage()); - twn_hm.put("maxPercentTaxAmount", town.getMaxPercentTaxAmount()); - twn_hm.put("open", town.isOpen()); - twn_hm.put("public", town.isPublic()); - twn_hm.put("conquered", town.isConquered()); - twn_hm.put("conqueredDays", town.getConqueredDays()); - twn_hm.put("admindisabledpvp", town.isAdminDisabledPVP()); - twn_hm.put("adminenabledpvp", town.isAdminEnabledPVP()); - twn_hm.put("adminEnabledMobs", town.isAdminEnabledMobs()); - twn_hm.put("allowedToWar", town.isAllowedToWar()); - twn_hm.put("joinedNationAt", town.getJoinedNationAt()); - twn_hm.put("mapColorHexCode", town.getMapColorHexCode()); - twn_hm.put("movedHomeBlockAt", town.getMovedHomeBlockAt()); - twn_hm.put("forSale", town.isForSale()); - twn_hm.put("forSalePrice", town.getForSalePrice()); - twn_hm.put("forSaleTime", town.getForSaleTime()); - if (town.hasMeta()) - twn_hm.put("metadata", serializeMetadata(town)); - else - twn_hm.put("metadata", ""); - - twn_hm.put("homeblock", - town.hasHomeBlock() - ? town.getHomeBlock().getWorld().getName() + "#" + town.getHomeBlock().getX() + "#" - + town.getHomeBlock().getZ() - : ""); - - final Position spawnPos = town.spawnPosition(); - twn_hm.put("spawn", spawnPos != null ? String.join("#", spawnPos.serialize()) : ""); - // Outpost Spawns - StringBuilder outpostArray = new StringBuilder(); - if (town.hasOutpostSpawn()) - for (Position spawn : town.getOutpostSpawns()) { - outpostArray.append(String.join("#", spawn.serialize())).append(";"); - } - twn_hm.put("outpostSpawns", outpostArray.toString()); - if (town.hasValidUUID()) { - twn_hm.put("uuid", town.getUUID()); - } else { - twn_hm.put("uuid", UUID.randomUUID()); - } - twn_hm.put("registered", town.getRegistered()); - - twn_hm.put("ruined", town.isRuined()); - twn_hm.put("ruinedTime", town.getRuinedTime()); - twn_hm.put("neutral", town.isNeutral()); - - twn_hm.put("debtBalance", town.getDebtBalance()); - - if (town.getPrimaryJail() != null) - twn_hm.put("primaryJail", town.getPrimaryJail().getUUID()); - - twn_hm.put("trustedResidents", StringMgmt.join(toUUIDList(town.getTrustedResidents()), "#")); - twn_hm.put("trustedTowns", StringMgmt.join(town.getTrustedTownsUUIDS(), "#")); - - twn_hm.put("allies", StringMgmt.join(town.getAlliesUUIDs(), "#")); - - twn_hm.put("enemies", StringMgmt.join(town.getEnemiesUUIDs(), "#")); - twn_hm.put("hasActiveWar", town.hasActiveWar()); - - updateDB("TOWNS", twn_hm, Collections.singletonList("uuid")); + updateDB("RESIDENTS", data, Collections.singletonList("uuid")); return true; - } catch (Exception e) { - plugin.getLogger().log(Level.WARNING, "SQL: Save Town unknown error", e); + TownyMessaging.sendErrorMsg("SQL: Save Resident unknown error " + e.getMessage()); } return false; } - + @Override - public synchronized boolean savePlotGroup(PlotGroup group) { - TownyMessaging.sendDebugMsg("Saving group " + group.getName()); + public synchronized boolean saveHibernatedResident(UUID uuid, Map data) { + TownyMessaging.sendDebugMsg("Saving Hibernated Resident " + uuid); try { - HashMap pltgrp_hm = new HashMap<>(); - pltgrp_hm.put("groupID", group.getUUID().toString()); - pltgrp_hm.put("groupName", group.getName()); - pltgrp_hm.put("groupPrice", group.getPrice()); - pltgrp_hm.put("town", group.getTown().getUUID()); - pltgrp_hm.put("metadata", serializeMetadata(group)); - - updateDB("PLOTGROUPS", pltgrp_hm, Collections.singletonList("groupID")); - + updateDB("HIBERNATEDRESIDENTS", data, Collections.singletonList("uuid")); + return true; } catch (Exception e) { - plugin.getLogger().log(Level.WARNING, "SQL: Save Plot groups unknown error", e); + TownyMessaging.sendErrorMsg("SQL: Save Hibernated Resident unknown error " + e.getMessage()); } return false; } @Override - public boolean saveDistrict(District district) { - TownyMessaging.sendDebugMsg("Saving district " + district.getName()); + public synchronized boolean saveTown(Town town, Map data) { + TownyMessaging.sendDebugMsg("Saving town " + town.getName()); try { - HashMap pltgrp_hm = new HashMap<>(); - pltgrp_hm.put("uuid", district.getUUID().toString()); - pltgrp_hm.put("districtName", district.getName()); - pltgrp_hm.put("town", district.getTown().getUUID().toString()); - pltgrp_hm.put("metadata", serializeMetadata(district)); - - updateDB("DISTRICTS", pltgrp_hm, Collections.singletonList("uuid")); - + updateDB("TOWNS", data, Collections.singletonList("uuid")); + return true; } catch (Exception e) { - plugin.getLogger().log(Level.WARNING, "SQL: Save Districts unknown error", e); + TownyMessaging.sendErrorMsg("SQL: Save Town unknown error"); + e.printStackTrace(); } return false; } @Override - public synchronized boolean saveNation(Nation nation) { - + public synchronized boolean saveNation(Nation nation, Map data) { TownyMessaging.sendDebugMsg("Saving nation " + nation.getName()); try { - HashMap nat_hm = new HashMap<>(); - nat_hm.put("name", nation.getName()); - nat_hm.put("capital", nation.hasCapital() ? nation.getCapital().getUUID() : ""); - nat_hm.put("nationBoard", nation.getBoard()); - nat_hm.put("mapColorHexCode", nation.getMapColorHexCode()); - nat_hm.put("tag", nation.hasTag() ? nation.getTag() : ""); - nat_hm.put("allies", StringMgmt.join(toUUIDList(nation.getAllies()), "#")); - nat_hm.put("enemies", StringMgmt.join(toUUIDList(nation.getEnemies()), "#")); - nat_hm.put("taxes", nation.getTaxes()); - nat_hm.put("taxpercent", nation.isTaxPercentage()); - nat_hm.put("maxPercentTaxAmount", nation.getMaxPercentTaxAmount()); - nat_hm.put("spawnCost", nation.getSpawnCost()); - nat_hm.put("neutral", nation.isNeutral()); - nat_hm.put("manualNationLevel", nation.getManualNationLevel()); - - final Position spawnPos = nation.spawnPosition(); - nat_hm.put("nationSpawn", spawnPos != null ? String.join("#", spawnPos.serialize()) : ""); - if (nation.hasValidUUID()) { - nat_hm.put("uuid", nation.getUUID()); - } else { - nat_hm.put("uuid", UUID.randomUUID()); - } - nat_hm.put("registered", nation.getRegistered()); - nat_hm.put("isPublic", nation.isPublic()); - nat_hm.put("isOpen", nation.isOpen()); - - if (nation.hasMeta()) - nat_hm.put("metadata", serializeMetadata(nation)); - else - nat_hm.put("metadata", ""); - - nat_hm.put("conqueredTax", nation.getConqueredTax()); - nat_hm.put("sanctionedTowns", StringMgmt.join(nation.getSanctionedTownsForSaving(), "#")); - nat_hm.put("hasActiveWar", nation.hasActiveWar()); - updateDB("NATIONS", nat_hm, Collections.singletonList("uuid")); - + updateDB("NATIONS", data, Collections.singletonList("uuid")); + return true; } catch (Exception e) { - plugin.getLogger().log(Level.WARNING, "SQL: Save Nation unknown error", e); + TownyMessaging.sendErrorMsg("SQL: Save Nation unknown error"); + e.printStackTrace(); } return false; } @Override - public synchronized boolean saveWorld(TownyWorld world) { - + public synchronized boolean saveWorld(TownyWorld world, Map data) { TownyMessaging.sendDebugMsg("Saving world " + world.getName()); try { - HashMap nat_hm = new HashMap<>(); - - nat_hm.put("name", world.getName()); - - nat_hm.put("uuid", world.getUUID()); - - // PvP - nat_hm.put("pvp", world.isPVP()); - // Force PvP - nat_hm.put("forcepvp", world.isForcePVP()); - // Friendly Fire - nat_hm.put("friendlyFire", world.isFriendlyFireEnabled()); - // Claimable - nat_hm.put("claimable", world.isClaimable()); - // has monster spawns - nat_hm.put("worldmobs", world.hasWorldMobs()); - // has wilderness monster spawns - nat_hm.put("wildernessmobs", world.hasWildernessMobs()); - // force town mob spawns - nat_hm.put("forcetownmobs", world.isForceTownMobs()); - // has firespread enabled - nat_hm.put("firespread", world.isFire()); - nat_hm.put("forcefirespread", world.isForceFire()); - // has explosions enabled - nat_hm.put("explosions", world.isExpl()); - nat_hm.put("forceexplosions", world.isForceExpl()); - // Enderman block protection - nat_hm.put("endermanprotect", world.isEndermanProtect()); - // CreatureTrample - nat_hm.put("disablecreaturetrample", world.isDisableCreatureTrample()); - - // Unclaimed Zone Build - nat_hm.put("unclaimedZoneBuild", world.getUnclaimedZoneBuild()); - // Unclaimed Zone Destroy - nat_hm.put("unclaimedZoneDestroy", world.getUnclaimedZoneDestroy()); - // Unclaimed Zone Switch - nat_hm.put("unclaimedZoneSwitch", world.getUnclaimedZoneSwitch()); - // Unclaimed Zone Item Use - nat_hm.put("unclaimedZoneItemUse", world.getUnclaimedZoneItemUse()); - // Unclaimed Zone Name - if (world.getUnclaimedZoneName() != null) - nat_hm.put("unclaimedZoneName", world.getUnclaimedZoneName()); - - // Unclaimed Zone Ignore Ids - if (world.getUnclaimedZoneIgnoreMaterials() != null) - nat_hm.put("unclaimedZoneIgnoreIds", StringMgmt.join(world.getUnclaimedZoneIgnoreMaterials(), "#")); - - // Deleting EntityTypes from Townblocks on Unclaim. - nat_hm.put("isDeletingEntitiesOnUnclaim", world.isDeletingEntitiesOnUnclaim()); - if (world.getUnclaimDeleteEntityTypes() != null) - nat_hm.put("unclaimDeleteEntityTypes", StringMgmt.join(BukkitTools.convertKeyedToString(world.getUnclaimDeleteEntityTypes()), "#")); - - // Using PlotManagement Delete - nat_hm.put("usingPlotManagementDelete", world.isUsingPlotManagementDelete()); - // Plot Management Delete Ids - if (world.getPlotManagementDeleteIds() != null) - nat_hm.put("plotManagementDeleteIds", StringMgmt.join(world.getPlotManagementDeleteIds(), "#")); - - // Using PlotManagement Mayor Delete - nat_hm.put("usingPlotManagementMayorDelete", world.isUsingPlotManagementMayorDelete()); - // Plot Management Mayor Delete - if (world.getPlotManagementMayorDelete() != null) - nat_hm.put("plotManagementMayorDelete", StringMgmt.join(world.getPlotManagementMayorDelete(), "#")); - - // Using PlotManagement Revert - nat_hm.put("usingPlotManagementRevert", world.isUsingPlotManagementRevert()); - - // Plot Management Ignore Ids - if (world.getPlotManagementIgnoreIds() != null) - nat_hm.put("plotManagementIgnoreIds", StringMgmt.join(world.getPlotManagementIgnoreIds(), "#")); - - // Revert on Unclaim whitelisted materials - if (world.getRevertOnUnclaimWhitelistMaterials() != null) - nat_hm.put("revertOnUnclaimWhitelistMaterials", StringMgmt.join(world.getRevertOnUnclaimWhitelistMaterials(), "#")); - - // Using PlotManagement Wild Regen - nat_hm.put("usingPlotManagementWildRegen", world.isUsingPlotManagementWildEntityRevert()); - - // Wilderness Explosion Protection entities - if (world.getPlotManagementWildRevertEntities() != null) - nat_hm.put("PlotManagementWildRegenEntities", StringMgmt.join(BukkitTools.convertKeyedToString(world.getPlotManagementWildRevertEntities()), "#")); - - // Wilderness Explosion Protection Block Whitelist - if (world.getPlotManagementWildRevertBlockWhitelist() != null) - nat_hm.put("PlotManagementWildRegenBlockWhitelist", - StringMgmt.join(world.getPlotManagementWildRevertBlockWhitelist(), "#")); - - // Wilderness Explosion Protection Materials to not overwrite. - if (world.getWildRevertMaterialsToNotOverwrite() != null) - nat_hm.put("wildRegenBlocksToNotOverwrite", - StringMgmt.join(world.getWildRevertMaterialsToNotOverwrite(), "#")); - - // Using PlotManagement Wild Regen Delay - nat_hm.put("plotManagementWildRegenSpeed", world.getPlotManagementWildRevertDelay()); - - // Using PlotManagement Wild Block Regen - nat_hm.put("usingPlotManagementWildRegenBlocks", world.isUsingPlotManagementWildBlockRevert()); - - // Wilderness Explosion Protection blocks - if (world.getPlotManagementWildRevertBlocks() != null) - nat_hm.put("PlotManagementWildRegenBlocks", - StringMgmt.join(world.getPlotManagementWildRevertBlocks(), "#")); - - // Using Towny - nat_hm.put("usingTowny", world.isUsingTowny()); - - // War allowed in this world. - nat_hm.put("warAllowed", world.isWarAllowed()); - - nat_hm.put("jailing", world.isJailingEnabled()); - - if (world.hasMeta()) - nat_hm.put("metadata", serializeMetadata(world)); - else - nat_hm.put("metadata", ""); - - updateDB("WORLDS", nat_hm, Collections.singletonList("name")); - + updateDB("WORLDS", data, Collections.singletonList("uuid")); + return true; } catch (Exception e) { - plugin.getLogger().log(Level.WARNING, "SQL: Save world unknown error (" + world.getName() + ")", e); - return false; + TownyMessaging.sendErrorMsg("SQL: Save World unknown error (" + world.getName() + ")"); + e.printStackTrace(); } - return true; + return false; } @Override - public synchronized boolean saveTownBlock(TownBlock townBlock) { - + public synchronized boolean saveTownBlock(TownBlock townBlock, Map data) { TownyMessaging.sendDebugMsg("Saving town block " + townBlock.getWorld().getName() + ":" + townBlock.getX() + "x" + townBlock.getZ()); try { - HashMap tb_hm = new HashMap<>(); - tb_hm.put("world", townBlock.getWorld().getName()); - tb_hm.put("x", townBlock.getX()); - tb_hm.put("z", townBlock.getZ()); - tb_hm.put("name", townBlock.getName()); - tb_hm.put("price", townBlock.getPlotPrice()); - tb_hm.put("taxed", townBlock.isTaxed()); - tb_hm.put("town", townBlock.getTown().getUUID()); - tb_hm.put("resident", (townBlock.hasResident()) ? townBlock.getResidentOrNull().getUUID() : ""); - tb_hm.put("typeName", townBlock.getTypeName()); - tb_hm.put("outpost", townBlock.isOutpost()); - tb_hm.put("permissions", - (townBlock.isChanged()) ? townBlock.getPermissions().toString().replaceAll(",", "#") : ""); - tb_hm.put("changed", townBlock.isChanged()); - tb_hm.put("claimedAt", townBlock.getClaimedAt()); - tb_hm.put("minTownMembershipDays", townBlock.getMinTownMembershipDays()); - tb_hm.put("maxTownMembershipDays", townBlock.getMaxTownMembershipDays()); - if (townBlock.hasPlotObjectGroup()) - tb_hm.put("groupID", townBlock.getPlotObjectGroup().getUUID().toString()); - else - tb_hm.put("groupID", ""); - if (townBlock.hasDistrict()) - tb_hm.put("districtID", townBlock.getDistrict().getUUID().toString()); - else - tb_hm.put("districtID", ""); - if (townBlock.hasMeta()) - tb_hm.put("metadata", serializeMetadata(townBlock)); - else - tb_hm.put("metadata", ""); - - if (townBlock.hasTrustedResidents()) { - tb_hm.put("trustedResidents", StringMgmt.join(toUUIDList(townBlock.getTrustedResidents()), "#")); - } else { - tb_hm.put("trustedResidents", ""); - } - - if (townBlock.hasPermissionOverrides()) { - Map stringMap = new HashMap<>(); - for (Map.Entry entry : townBlock.getPermissionOverrides().entrySet()) { - stringMap.put(entry.getKey().getUUID().toString(), entry.getValue().toString()); - } - - tb_hm.put("customPermissionData", new Gson().toJson(stringMap)); - } else { - tb_hm.put("customPermissionData", ""); - } - - updateDB("TOWNBLOCKS", tb_hm, Arrays.asList("world", "x", "z")); - + updateDB("TOWNBLOCKS", data, Arrays.asList("world", "x", "z")); + return true; } catch (Exception e) { - plugin.getLogger().log(Level.WARNING, "SQL: Save TownBlock unknown error", e); + TownyMessaging.sendErrorMsg("SQL: Save TownBlock unknown error"); + e.printStackTrace(); } - return true; + return false; } + @Override - public synchronized boolean saveJail(Jail jail) { - - TownyMessaging.sendDebugMsg("Saving jail " + jail.getUUID()); - - try { - HashMap jail_hm = new HashMap<>(); - jail_hm.put("uuid", jail.getUUID()); - jail_hm.put("townBlock", jail.getTownBlock().getWorld().getName() + "#" + jail.getTownBlock().getX() + "#" + jail.getTownBlock().getZ()); - - StringBuilder jailCellArray = new StringBuilder(); - if (jail.hasCells()) - for (Position cell : jail.getJailCellPositions()) { - jailCellArray.append(String.join("#", cell.serialize())).append(";"); - } - - jail_hm.put("spawns", jailCellArray); + public boolean loadCooldowns() { + try (Connection connection = getConnection(); + PreparedStatement statement = connection.prepareStatement("SELECT * FROM " + tb_prefix + TownyDBTableType.COOLDOWN.tableName()); + ResultSet resultSet = statement.executeQuery()) { - updateDB("JAILS", jail_hm, Collections.singletonList("uuid")); - return true; - } catch (Exception e) { - plugin.getLogger().log(Level.WARNING, "SQL: Save jail unknown error", e); + while (resultSet.next()) + CooldownTimerTask.getCooldowns().put(resultSet.getString("key"), resultSet.getLong("expiry")); + } catch (SQLException e) { + plugin.getLogger().log(Level.WARNING, "An exception occurred when loading cooldowns", e); + return false; } + return true; + } + + @Override + public boolean saveCooldowns() { + for (Map.Entry entry : CooldownTimerTask.getCooldowns().entrySet()) { + final Map data = new HashMap<>(); + data.put("key", entry.getKey()); + data.put("expiry", entry.getValue()); + + queueUpdateDB(TownyDBTableType.COOLDOWN.tableName(), data, Collections.singletonList("key")); + } + return true; } /* @@ -2840,4 +1003,5 @@ public CompletableFuture> getHibernatedResidentRegistered(UUID uu public HikariDataSource getHikariDataSource() { return hikariDataSource; } + } diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/exceptions/ObjectCouldNotBeLoadedException.java b/Towny/src/main/java/com/palmergames/bukkit/towny/exceptions/ObjectCouldNotBeLoadedException.java new file mode 100644 index 00000000000..f7c94b4025d --- /dev/null +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/exceptions/ObjectCouldNotBeLoadedException.java @@ -0,0 +1,10 @@ +package com.palmergames.bukkit.towny.exceptions; + +public class ObjectCouldNotBeLoadedException extends TownyException { + + private static final long serialVersionUID = 4578331852742763913L; + + public ObjectCouldNotBeLoadedException(String message) { + super(message); + } +} diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/exceptions/ObjectSaveException.java b/Towny/src/main/java/com/palmergames/bukkit/towny/exceptions/ObjectSaveException.java new file mode 100644 index 00000000000..dd0cf585306 --- /dev/null +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/exceptions/ObjectSaveException.java @@ -0,0 +1,14 @@ +package com.palmergames.bukkit.towny.exceptions; + +public class ObjectSaveException extends TownyException { + + private static final long serialVersionUID = 2434653565991348834L; + + public ObjectSaveException(String message) { + super(message); + } + + public ObjectSaveException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/object/District.java b/Towny/src/main/java/com/palmergames/bukkit/towny/object/District.java index c0b4405ad6f..95191bc1c1b 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/object/District.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/object/District.java @@ -1,13 +1,19 @@ package com.palmergames.bukkit.towny.object; +import com.palmergames.bukkit.towny.Towny; import com.palmergames.bukkit.towny.TownyMessaging; import com.palmergames.bukkit.towny.TownyUniverse; +import com.palmergames.bukkit.towny.exceptions.ObjectSaveException; +import com.palmergames.bukkit.towny.object.metadata.MetadataLoader; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.UUID; +import java.util.logging.Level; /** * @author LlmDl @@ -130,4 +136,51 @@ public boolean hasTownBlock(TownBlock townBlock) { public void save() { TownyUniverse.getInstance().getDataSource().saveDistrict(this); } + + @Override + public Map getObjectDataMap() throws ObjectSaveException { + try { + Map district_hm = new HashMap<>(); + district_hm.put("districtName", getName()); + district_hm.put("town", getTown().getUUID()); + district_hm.put("metadata", hasMeta() ? serializeMetadata(this) : ""); + + return district_hm; + + } catch (Exception e) { + throw new ObjectSaveException("An exception occurred when constructing data for plot group " + getName() + " (" + getUUID() + "), caused by: " + e.getMessage()); + } + } + + public boolean load(Map districtAsMap) { + String line = ""; + try { + line = districtAsMap.get("town"); + if (hasData(line)) { + Town town = TownyUniverse.getInstance().getTown(UUID.fromString(line)); + if (town != null) { + setTown(town); + setName(districtAsMap.getOrDefault("districtName", "")); + line = districtAsMap.get("metadata"); + if (hasData(line)) + MetadataLoader.getInstance().deserializeMetadata(this, line.trim()); + } else { + TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_district_file_missing_town_delete", getUUID())); + TownyUniverse.getInstance().getDataSource().deleteDistrict(this); + TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_missing_file_delete_district_entry", getUUID())); + return true; + } + } else { + TownyMessaging.sendErrorMsg(Translation.of("flatfile_err_could_not_add_to_town")); + TownyUniverse.getInstance().getDataSource().deleteDistrict(this); + return true; + } + if (exists()) + save(); + return true; + } catch (Exception e) { + Towny.getPlugin().getLogger().log(Level.WARNING, Translation.of("flatfile_err_exception_reading_district_file_at_line", getUUID(), line), e); + return false; + } + } } diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/object/Loadable.java b/Towny/src/main/java/com/palmergames/bukkit/towny/object/Loadable.java new file mode 100644 index 00000000000..3cd2604f0f0 --- /dev/null +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/object/Loadable.java @@ -0,0 +1,168 @@ +package com.palmergames.bukkit.towny.object; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; + +import org.bukkit.Location; +import org.bukkit.World; +import org.jetbrains.annotations.Nullable; + +import com.palmergames.bukkit.towny.TownyAPI; +import com.palmergames.bukkit.towny.TownyUniverse; +import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; +import com.palmergames.bukkit.towny.object.metadata.DataFieldIO; +import com.palmergames.bukkit.util.BukkitTools; + +public abstract class Loadable { + + protected TownBlock parseTownBlockFromDB(String input) throws NumberFormatException, NotRegisteredException { + String[] tokens = input.split(getSplitter(input)); + TownyUniverse universe = TownyUniverse.getInstance(); + try { + UUID uuid = UUID.fromString(tokens[0]); + if (universe.getWorld(uuid) == null) + throw new NotRegisteredException("TownBlock tried to load an invalid world!"); + return universe.getTownBlock(new WorldCoord(universe.getWorld(uuid).getName(), uuid, Integer.parseInt(tokens[1].trim()), Integer.parseInt(tokens[2].trim()))); + } catch (IllegalArgumentException e) { // Legacy DB used Names instead of UUIDs. + if (universe.getWorld(tokens[0]) == null) + throw new NotRegisteredException("TownBlock tried to load an invalid world!"); + return universe.getTownBlock(new WorldCoord(tokens[0], Integer.parseInt(tokens[1].trim()), Integer.parseInt(tokens[2].trim()))); + } + } + + @Nullable + protected List getResidentsFromDB(String line) { + List residents = new ArrayList<>(); + try { + residents = TownyAPI.getInstance().getResidents(toUUIDArray(line.split("#"))); + } catch (IllegalArgumentException e) { // Legacy DB used Names instead of UUIDs. + residents = TownyAPI.getInstance().getResidents(line.split(",")); + } + return residents; + } + + @Nullable + protected List getTownsFromDB(String line) { + List towns = new ArrayList<>(); + try { + towns = TownyAPI.getInstance().getTowns(toUUIDArray(line.split("#"))); + } catch (IllegalArgumentException e) { // Legacy DB used Names instead of UUIDs. + towns = TownyAPI.getInstance().getTowns(line.split(",")); + } + return towns; + } + + @Nullable + protected List getNationsFromDB(String line) { + List nations = new ArrayList<>(); + try { + nations = TownyAPI.getInstance().getNations(toUUIDArray(line.split("#"))); + } catch (IllegalArgumentException e) { // Legacy DB used Names instead of UUIDs. + nations = TownyAPI.getInstance().getNations(line.split(",")); + } + return nations; + } + + @Nullable + protected Location parseSpawnLocationFromDB(String raw) { + String[] tokens = raw.split(getSplitter(raw)); + if (tokens.length >= 4) + try { + World world = null; + try { + world = BukkitTools.getWorld(UUID.fromString(tokens[0])); + } catch (IllegalArgumentException e) { // Legacy DB used Names instead of UUIDs. + world = BukkitTools.getWorld(tokens[0]); + } + if (world == null) + return null; + double x = Double.parseDouble(tokens[1]); + double y = Double.parseDouble(tokens[2]); + double z = Double.parseDouble(tokens[3]); + + Location loc = new Location(world, x, y, z); + if (tokens.length == 6) { + loc.setPitch(Float.parseFloat(tokens[4])); + loc.setYaw(Float.parseFloat(tokens[5])); + } + return loc; + } catch (NumberFormatException | NullPointerException ignored) { + } + return null; + } + + protected boolean getOrDefault(Map keys, String key, boolean bool) { + return Boolean.parseBoolean(keys.getOrDefault(key, String.valueOf(bool))); + } + + protected long getOrDefault(Map keys, String key, long num) { + return Long.parseLong(keys.getOrDefault(key, String.valueOf(num))); + } + + protected double getOrDefault(Map keys, String key, double num) { + return Double.parseDouble(keys.getOrDefault(key, String.valueOf(num))); + } + + protected int getOrDefault(Map keys, String key, int num) { + return Integer.parseInt(keys.getOrDefault(key, String.valueOf(num))); + } + + protected boolean hasData(String line) { + return line != null && !line.isEmpty(); + } + + protected UUID[] toUUIDArray(String[] uuidArray) throws IllegalArgumentException { + UUID[] uuids = new UUID[uuidArray.length]; + + for (int i = 0; i < uuidArray.length; i++) + uuids[i] = UUID.fromString(uuidArray[i]); + + return uuids; + } + + protected List toList(String string) { + List mats = new ArrayList<>(); + if (string != null) + try { + for (String s : string.split(getSplitter(string))) + if (!s.isEmpty()) + mats.add(s); + } catch (Exception ignored) { + } + return mats; + } + + /** + * Legacy DB used , instead of #. + * @param raw Text from DB + * @return splitter character. + */ + protected String getSplitter(String raw) { + return raw.contains("#") ? "#" : ","; + } + + protected String serializeMetadata(TownyObject obj) { + return DataFieldIO.serializeCDFs(obj.getMetadata()); + } + + protected String getTownBlockForSaving(TownBlock tb) { + return tb.getWorld().getUUID() + "#" + tb.getX() + "#" + tb.getZ(); + } + + protected String parseLocationForSaving(Location loc) { + return loc.getWorld().getUID() + "#" + + loc.getX() + "#" + + loc.getY() + "#" + + loc.getZ() + "#" + + loc.getPitch() + "#" + + loc.getYaw(); + } + + protected List toUUIDList(Collection residents) { + return residents.stream().filter(Resident::hasUUID).map(Resident::getUUID).collect(Collectors.toList()); + } +} diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/object/Nation.java b/Towny/src/main/java/com/palmergames/bukkit/towny/object/Nation.java index 353e3a3076d..e8629f7daae 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/object/Nation.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/object/Nation.java @@ -1,38 +1,53 @@ package com.palmergames.bukkit.towny.object; +import com.palmergames.bukkit.towny.Towny; import com.palmergames.bukkit.towny.TownyAPI; import com.palmergames.bukkit.towny.TownyEconomyHandler; import com.palmergames.bukkit.towny.TownyMessaging; import com.palmergames.bukkit.towny.TownySettings; import com.palmergames.bukkit.towny.TownySettings.NationLevel; import com.palmergames.bukkit.towny.TownyUniverse; +import com.palmergames.bukkit.towny.event.DeleteNationEvent.Cause; import com.palmergames.bukkit.towny.event.TownyObjectFormattedNameEvent; +import com.palmergames.bukkit.towny.exceptions.AlreadyRegisteredException; import com.palmergames.bukkit.towny.exceptions.EmptyNationException; +import com.palmergames.bukkit.towny.exceptions.ObjectSaveException; import com.palmergames.bukkit.towny.exceptions.TownyException; import com.palmergames.bukkit.towny.invites.Invite; import com.palmergames.bukkit.towny.invites.InviteHandler; import com.palmergames.bukkit.towny.invites.exceptions.TooManyInvitesException; import com.palmergames.bukkit.towny.object.SpawnPoint.SpawnPointType; import com.palmergames.bukkit.towny.object.metadata.CustomDataField; +import com.palmergames.bukkit.towny.object.metadata.MetadataLoader; import com.palmergames.bukkit.towny.permissions.TownyPerms; +import com.palmergames.bukkit.towny.utils.MapUtil; import com.palmergames.bukkit.towny.utils.NationUtil; import com.palmergames.bukkit.towny.utils.ProximityUtil; import com.palmergames.bukkit.towny.utils.TownyComponents; import com.palmergames.bukkit.util.BukkitTools; +import com.palmergames.util.StringMgmt; + import net.kyori.adventure.audience.Audience; + import org.bukkit.Location; import org.bukkit.World; import org.bukkit.entity.Player; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.Unmodifiable; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.UUID; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.stream.Collectors; public class Nation extends Government { @@ -41,8 +56,8 @@ public class Nation extends Government { private final List towns = new ArrayList<>(); private final List sanctionedTowns = new ArrayList<>(); - private List allies = new ArrayList<>(); - private List enemies = new ArrayList<>(); + private final Map allies = new LinkedHashMap<>(); + private final Map enemies = new LinkedHashMap<>(); private Town capital; private final List sentAllyInvites = new ArrayList<>(); private boolean isTaxPercentage = TownySettings.getNationDefaultTaxPercentage(); @@ -285,24 +300,44 @@ public List getAssistants() { return this.getResidents().stream().filter(assistant -> assistant.hasNationRank("assistant")).collect(Collectors.toList()); } - public void setEnemies(List enemies) { + public void loadEnemies(List nations) { + for (Nation nation : nations) + enemies.put(nation.getUUID(), nation); + } - this.enemies = enemies; + public List getEnemiesUUIDs() { + //noinspection Java9CollectionFactory + return Collections.unmodifiableList(new ArrayList<>(enemies.keySet())); + } + + public void setEnemies(List enemies) { + this.enemies.clear(); + loadEnemies(enemies); } public List getEnemies() { + //noinspection Java9CollectionFactory + return Collections.unmodifiableList(new ArrayList<>(enemies.values())); + } - return enemies; + public void loadAllies(List nations) { + for (Nation nation : nations) + allies.put(nation.getUUID(), nation); } - public void setAllies(List allies) { + @Unmodifiable + public List getAlliesUUIDs() { + return Collections.unmodifiableList(new ArrayList<>(allies.keySet())); + } - this.allies = allies; + public void setAllies(List allies) { + this.allies.clear(); + loadAllies(allies); } public List getAllies() { - - return allies; + //noinspection Java9CollectionFactory + return Collections.unmodifiableList(new ArrayList<>(allies.values())); } public boolean hasReachedMaximumAllies() { @@ -607,14 +642,130 @@ public double getBankCap() { * @return true if it is allied, false otherwise. */ public boolean isAlliedWith(Nation nation) { - return allies.contains(nation); + return allies.containsKey(nation.getUUID()); } @Override public void save() { TownyUniverse.getInstance().getDataSource().saveNation(this); } - + + @Override + public Map getObjectDataMap() throws ObjectSaveException { + try { + Map nat_hm = new HashMap<>(); + nat_hm.put("name", getName()); + nat_hm.put("capital", hasCapital() ? getCapital().getUUID() : ""); + nat_hm.put("capitalName", hasCapital() ? getCapital().getName() : ""); + nat_hm.put("tag", hasTag() ? getTag() : ""); + nat_hm.put("allies", StringMgmt.join(getAlliesUUIDs(), "#")); + nat_hm.put("enemies", StringMgmt.join(getEnemiesUUIDs(), "#")); + nat_hm.put("taxes", getTaxes()); + nat_hm.put("taxpercent", isTaxPercentage()); + nat_hm.put("maxPercentTaxAmount", getMaxPercentTaxAmount()); + nat_hm.put("spawnCost", getSpawnCost()); + nat_hm.put("neutral", isNeutral()); + nat_hm.put("registered", getRegistered()); + nat_hm.put("nationBoard", getBoard()); + nat_hm.put("mapColorHexCode", getMapColorHexCode()); + nat_hm.put("manualNationLevel", getManualNationLevel()); + nat_hm.put("nationSpawn", hasSpawn() ? parseLocationForSaving(getSpawn()) : ""); + nat_hm.put("isPublic", isPublic()); + nat_hm.put("isOpen", isOpen()); + nat_hm.put("conqueredTax", getConqueredTax()); + nat_hm.put("sanctionedTowns", StringMgmt.join(getSanctionedTownsForSaving(), "#")); + nat_hm.put("hasActiveWar", hasActiveWar()); + nat_hm.put("metadata", hasMeta() ? serializeMetadata(this) : ""); + return nat_hm; + } catch (Exception e) { + throw new ObjectSaveException("An exception occurred when constructing data for nation " + getName() + " (" + getUUID() + "), caused by: " + e.getMessage()); + } + } + + public boolean load(Map dataAsMap) { + String line = ""; + TownyUniverse universe = TownyUniverse.getInstance(); + Logger logger = Towny.getPlugin().getLogger(); + try { + line = dataAsMap.get("capital"); + String cantLoadCapital = Translation.of("flatfile_err_nation_could_not_load_capital_disband", getName()); + if (line != null) { + Town town = universe.getTown(UUID.fromString(line)); + if (town != null) { + try { + forceSetCapital(town); + } catch (EmptyNationException e1) { + logger.warning(cantLoadCapital); + TownyUniverse.getInstance().getDataSource().removeNation(this, Cause.NO_TOWNS); + return true; + } + } + else { + TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_cannot_set_capital_try_next", getName(), line)); + if (!findNewCapital()) { + logger.warning(cantLoadCapital); + TownyUniverse.getInstance().getDataSource().removeNation(this, Cause.NO_TOWNS); + return true; + } + } + } else { + TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_undefined_capital_select_new", getName())); + if (!findNewCapital()) { + logger.warning(cantLoadCapital); + TownyUniverse.getInstance().getDataSource().removeNation(this, Cause.NO_TOWNS); + return true; + } + } + setTag(dataAsMap.getOrDefault("tag", "")); + line = dataAsMap.get("allies"); + if (hasData(line)) + loadAllies(getNationsFromDB(line)); + + line = dataAsMap.get("enemies"); + if (hasData(line)) + loadEnemies(getNationsFromDB(line)); + setTaxes(getOrDefault(dataAsMap, "taxes", 0.0)); + setTaxPercentage(getOrDefault(dataAsMap, "taxpercent", TownySettings.getNationDefaultTaxPercentage())); + setMaxPercentTaxAmount(getOrDefault(dataAsMap, "maxPercentTaxAmount", TownySettings.getMaxNationTaxPercentAmount())); + setConqueredTax(getOrDefault(dataAsMap, "conqueredTax", TownySettings.getDefaultNationConqueredTaxAmount())); + setSpawnCost(getOrDefault(dataAsMap, "spawnCost", TownySettings.getSpawnTravelCost())); + setNeutral(getOrDefault(dataAsMap, "neutral", false)); + setRegistered(getOrDefault(dataAsMap, "registered", 0l)); + setPublic(getOrDefault(dataAsMap, "isPublic", false)); + setOpen(getOrDefault(dataAsMap, "isOpen", TownySettings.getNationDefaultOpen())); + setBoard(dataAsMap.getOrDefault("nationBoard", TownySettings.getNationDefaultBoard())); + setMapColorHexCode(dataAsMap.getOrDefault("mapColorHexCode", MapUtil.generateRandomNationColourAsHexCode())); + setActiveWar(getOrDefault(dataAsMap, "hasActiveWar", false)); + setManualNationLevel(getOrDefault(dataAsMap, "manualNationLevel", -1)); + + line = dataAsMap.get("sanctionedTowns"); + if (hasData(line)) + loadSanctionedTowns(getTownsFromDB(line)); + + line = dataAsMap.get("nationSpawn"); + if (hasData(line)) { + Location loc = parseSpawnLocationFromDB(line); + if (loc != null) + setSpawn(loc); + } + + line = dataAsMap.get("metadata"); + if (hasData(line)) + MetadataLoader.getInstance().deserializeMetadata(this, line.trim()); + + try { + universe.registerNation(this); + } catch (AlreadyRegisteredException ignored) {} + if (exists()) + save(); + + } catch (Exception e) { + logger.log(Level.WARNING, Translation.of("flatfile_err_reading_nation_file_at_line", getName(), line, getUUID().toString()), e); + return false; + } + return true; + } + @Override public int getNationZoneSize() { if (!TownySettings.getNationZonesEnabled()) @@ -696,16 +847,8 @@ public List getSanctionedTownsForSaving() { return sanctionedTowns.stream().map(t -> t.getUUID().toString()).collect(Collectors.toList()); } - public void loadSanctionedTowns(String[] tokens) { - for (String stringUUID : tokens) { - try { - Town town = TownyAPI.getInstance().getTown(UUID.fromString(stringUUID)); - if (town != null) - sanctionedTowns.add(town); - } catch (IllegalArgumentException ignored) { - continue; - } - } + public void loadSanctionedTowns(@Nullable List towns) { + towns.forEach(t -> addSanctionedTown(t)); } diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/object/PlotGroup.java b/Towny/src/main/java/com/palmergames/bukkit/towny/object/PlotGroup.java index df9e74a1150..9de019b4491 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/object/PlotGroup.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/object/PlotGroup.java @@ -1,16 +1,21 @@ package com.palmergames.bukkit.towny.object; +import com.palmergames.bukkit.towny.Towny; import com.palmergames.bukkit.towny.TownyMessaging; import com.palmergames.bukkit.towny.TownyUniverse; +import com.palmergames.bukkit.towny.exceptions.ObjectSaveException; +import com.palmergames.bukkit.towny.object.metadata.MetadataLoader; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; +import java.util.logging.Level; import org.jetbrains.annotations.Nullable; @@ -171,6 +176,55 @@ public void save() { TownyUniverse.getInstance().getDataSource().savePlotGroup(this); } + @Override + public Map getObjectDataMap() throws ObjectSaveException { + try { + Map pltgrp_hm = new HashMap<>(); + pltgrp_hm.put("groupName", getName()); + pltgrp_hm.put("groupPrice", getPrice()); + pltgrp_hm.put("town", getTown().getUUID()); + pltgrp_hm.put("metadata", hasMeta() ? serializeMetadata(this) : ""); + + return pltgrp_hm; + + } catch (Exception e) { + throw new ObjectSaveException("An exception occurred when constructing data for plot group " + getName() + " (" + getUUID() + "), caused by: " + e.getMessage()); + } + } + + public boolean load(Map groupAsMap) { + String line = ""; + try { + line = groupAsMap.get("town"); + if (hasData(line)) { + Town town = TownyUniverse.getInstance().getTown(UUID.fromString(line)); + if (town != null) { + setTown(town); + setName(groupAsMap.getOrDefault("groupName", "")); + setPrice(getOrDefault(groupAsMap, "groupPrice", -1.0)); + line = groupAsMap.get("metadata"); + if (hasData(line)) + MetadataLoader.getInstance().deserializeMetadata(this, line.trim()); + } else { + TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_group_file_missing_town_delete", getUUID())); + TownyUniverse.getInstance().getDataSource().deletePlotGroup(this); + TownyMessaging.sendDebugMsg(Translation.of("flatfile_dbg_missing_file_delete_group_entry", getUUID())); + return true; + } + } else { + TownyMessaging.sendErrorMsg(Translation.of("flatfile_err_could_not_add_to_town")); + TownyUniverse.getInstance().getDataSource().deletePlotGroup(this); + return true; + } + if (exists()) + save(); + return true; + } catch (Exception e) { + Towny.getPlugin().getLogger().log(Level.WARNING, Translation.of("flatfile_err_exception_reading_group_file_at_line", getUUID(), line), e); + return false; + } + } + public void setTrustedResidents(Set trustedResidents) { this.trustedResidents = new LinkedHashSet<>(trustedResidents); } diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/object/Resident.java b/Towny/src/main/java/com/palmergames/bukkit/towny/object/Resident.java index 3a69fa3cc68..a5c0866c64a 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/object/Resident.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/object/Resident.java @@ -16,6 +16,7 @@ import com.palmergames.bukkit.towny.exceptions.AlreadyRegisteredException; import com.palmergames.bukkit.towny.exceptions.EmptyTownException; import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; +import com.palmergames.bukkit.towny.exceptions.ObjectSaveException; import com.palmergames.bukkit.towny.exceptions.TownyException; import com.palmergames.bukkit.towny.invites.Invite; import com.palmergames.bukkit.towny.invites.InviteHandler; @@ -26,6 +27,7 @@ import com.palmergames.bukkit.towny.object.jail.Jail; import com.palmergames.bukkit.towny.object.metadata.BooleanDataField; import com.palmergames.bukkit.towny.object.metadata.CustomDataField; +import com.palmergames.bukkit.towny.object.metadata.MetadataLoader; import com.palmergames.bukkit.towny.object.resident.mode.ResidentModeHandler; import com.palmergames.bukkit.towny.permissions.TownyPerms; import com.palmergames.bukkit.towny.scheduling.ScheduledTask; @@ -50,13 +52,17 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.UUID; +import java.util.logging.Level; import java.util.stream.Collectors; public class Resident extends TownyObject implements InviteReceiver, EconomyHandler, TownBlockOwner, Identifiable, ForwardingAudience.Single { - private List friends = new ArrayList<>(); + private final Map friends = new LinkedHashMap<>(); // private List regenUndo = new ArrayList<>(); // Feature is disabled as of MC 1.13, maybe it'll come back. private final UUID uuid; private Town town = null; @@ -372,24 +378,36 @@ public void removeTown(boolean townDeleted) { Towny.getPlugin().resetCache(); } - public void setFriends(List newFriends) { + /** + * Only to be used when loading the database. + * @param residents List<Resident> which will be loaded in as friends. + */ + public void loadFriends(List residents) { + for (Resident resident : residents) + friends.put(resident.getUUID(), resident); + } - friends = newFriends; + public List getFriendsUUIDs() { + //noinspection Java9CollectionFactory + return Collections.unmodifiableList(new ArrayList<>(friends.keySet())); + } + + public void setFriends(List newFriends) { + this.friends.clear(); + loadFriends(newFriends); } public List getFriends() { - return Collections.unmodifiableList(friends); + return Collections.unmodifiableList(new ArrayList<>(friends.values())); } public void removeFriend(Resident resident) { - - if (hasFriend(resident)) - friends.remove(resident); + friends.remove(resident.getUUID()); } public boolean hasFriend(Resident resident) { - return friends.contains(resident); + return friends.containsKey(resident.getUUID()); } public void addFriend(Resident resident){ @@ -397,11 +415,11 @@ public void addFriend(Resident resident){ if (hasFriend(resident) || this.equals(resident) || resident.isNPC()) return; - friends.add(resident); + friends.put(resident.getUUID(), resident); } public void removeAllFriends() { - // Wipe the array. + // Wipe the map. friends.clear(); } @@ -928,6 +946,123 @@ public void save() { TownyUniverse.getInstance().getDataSource().saveResident(this); } + @Override + public Map getObjectDataMap() throws ObjectSaveException { + try { + Map res_hm = new HashMap<>(); + res_hm.put("name", getName()); + res_hm.put("town", hasTown() ? getTown().getUUID() : ""); + res_hm.put("townName", hasTown() ? getTown().getName() : ""); + res_hm.put("town-ranks", hasTown() ? StringMgmt.join(getTownRanks(), "#") : ""); + res_hm.put("nation-ranks", hasTown() ? StringMgmt.join(getNationRanks(), "#") : ""); + res_hm.put("lastOnline", getLastOnline()); + res_hm.put("registered", getRegistered()); + res_hm.put("joinedTownAt", getJoinedTownAt()); + res_hm.put("isNPC", isNPC()); + res_hm.put("jailUUID", isJailed() ? getJail().getUUID() : ""); + res_hm.put("jailCell", getJailCell()); + res_hm.put("jailHours", getJailHours()); + res_hm.put("jailBail", getJailBailCost()); + res_hm.put("title", getTitle()); + res_hm.put("surname", getSurname()); + res_hm.put("protectionStatus", getPermissions().toString().replaceAll(",", "#")); + res_hm.put("friends", StringMgmt.join(getFriendsUUIDs(), "#")); + res_hm.put("about", getAbout()); + res_hm.put("metadata", hasMeta() ? serializeMetadata(this) : ""); + return res_hm; + } catch (Exception e) { + throw new ObjectSaveException("An exception occurred when constructing data for resident " + getName() + " (" + getUUID() + "), caused by: " + e.getMessage()); + } + } + + public boolean load(Map dataAsMap) { + String line = ""; + TownyUniverse universe = TownyUniverse.getInstance(); + + try { + line = dataAsMap.get("town"); + if (hasData(line)) { + Town town = universe.getTown(UUID.fromString(line)); + if (town == null) + TownyMessaging.sendErrorMsg(Translation.of("flatfile_err_resident_tried_load_invalid_town", getName(), line)); + + if (town != null) { + setTown(town, false); + + line = dataAsMap.get("title"); + if (hasData(line)) + setTitle(line); + + line = dataAsMap.get("surname"); + if (hasData(line)) + setSurname(line); + + try { + line = dataAsMap.get("town-ranks"); + if (hasData(line)) + setTownRanks(Arrays.asList(line.split(getSplitter(line)))); + } catch (Exception e) {} + + try { + line = dataAsMap.get("nation-ranks"); + if (hasData(line)) + setNationRanks(Arrays.asList(line.split(getSplitter(line)))); + } catch (Exception e) {} + + line = dataAsMap.get("joinedTownAt"); + if (hasData(line)) { + setJoinedTownAt(Long.valueOf(line)); + } + } + } + // Last Online Date + setLastOnline(getOrDefault(dataAsMap, "lastOnline", 0l)); + // Registered Date + setRegistered(getOrDefault(dataAsMap, "registered", 0l)); + // isNPC + setNPC(getOrDefault(dataAsMap, "isNPC", false)); + // about + setAbout(dataAsMap.getOrDefault("about", "")); + // jail + line = dataAsMap.get("jailUUID"); + if (hasData(line) && universe.hasJail(UUID.fromString(line))) + setJail(universe.getJail(UUID.fromString(line))); + if (isJailed()) { + line = dataAsMap.get("jailCell"); + if (hasData(line)) + setJailCell(Integer.parseInt(line)); + + line = dataAsMap.get("jailHours"); + if (hasData(line)) + setJailHours(Integer.parseInt(line)); + + line = dataAsMap.get("jailBail"); + if (hasData(line)) + setJailBailCost(Double.parseDouble(line)); + } + line = dataAsMap.get("friends"); + if (hasData(line)) + loadFriends(getResidentsFromDB(line)); + + setPermissions(dataAsMap.getOrDefault("protectionStatus", "")); + + line = dataAsMap.get("metadata"); + if (hasData(line)) + MetadataLoader.getInstance().deserializeMetadata(this, line.trim()); + + + try { + universe.registerResident(this); + } catch (AlreadyRegisteredException ignored) {} + if (exists()) + save(); + return true; + } catch (Exception e) { + Towny.getPlugin().getLogger().log(Level.WARNING, Translation.of("flatfile_err_reading_resident_at_line", getName(), line, getUUID()), e); + return false; + } + } + /** * Gets a list of Towns which the given resident owns embassy plots in. * @return List of Towns in which the resident owns embassies. diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/object/Savable.java b/Towny/src/main/java/com/palmergames/bukkit/towny/object/Savable.java index 36791da977f..314f43b6e0a 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/object/Savable.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/object/Savable.java @@ -1,5 +1,9 @@ package com.palmergames.bukkit.towny.object; +import java.util.Map; + +import com.palmergames.bukkit.towny.exceptions.ObjectSaveException; + /** * Basic interface that depicts whether an object has a specified save method. * Most, if not all, save methods will redirect to a specific method in {@link com.palmergames.bukkit.towny.db.TownyDataSource}. @@ -12,4 +16,11 @@ public interface Savable { * Schedules the object to be saved to the database. */ void save(); + + /** + * + * @return a Map which stores keys and values, meant to be written to a database. + * @throws ObjectSaveException when something cannot be saved. + */ + Map getObjectDataMap() throws ObjectSaveException; } diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/object/Town.java b/Towny/src/main/java/com/palmergames/bukkit/towny/object/Town.java index a1812c49562..804d5aa1fb7 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/object/Town.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/object/Town.java @@ -1,6 +1,7 @@ package com.palmergames.bukkit.towny.object; import com.google.common.collect.Lists; +import com.palmergames.bukkit.towny.Towny; import com.palmergames.bukkit.towny.TownyAPI; import com.palmergames.bukkit.towny.TownyEconomyHandler; import com.palmergames.bukkit.towny.TownyMessaging; @@ -29,17 +30,22 @@ import com.palmergames.bukkit.towny.exceptions.EmptyNationException; import com.palmergames.bukkit.towny.exceptions.EmptyTownException; import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; +import com.palmergames.bukkit.towny.exceptions.ObjectSaveException; import com.palmergames.bukkit.towny.exceptions.TownyException; import com.palmergames.bukkit.towny.object.SpawnPoint.SpawnPointType; import com.palmergames.bukkit.towny.object.jail.Jail; import com.palmergames.bukkit.towny.object.metadata.CustomDataField; +import com.palmergames.bukkit.towny.object.metadata.MetadataLoader; import com.palmergames.bukkit.towny.permissions.TownyPerms; import com.palmergames.bukkit.towny.utils.CombatUtil; +import com.palmergames.bukkit.towny.utils.MapUtil; import com.palmergames.bukkit.towny.utils.MoneyUtil; import com.palmergames.bukkit.towny.utils.ProximityUtil; import com.palmergames.bukkit.towny.utils.TownUtil; import com.palmergames.bukkit.towny.utils.TownyComponents; import com.palmergames.bukkit.util.BukkitTools; +import com.palmergames.util.StringMgmt; + import net.kyori.adventure.audience.Audience; import org.bukkit.Location; import org.bukkit.World; @@ -65,6 +71,7 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.logging.Level; import java.util.stream.Collectors; public class Town extends Government implements TownBlockOwner { @@ -1667,6 +1674,213 @@ public void save() { TownyUniverse.getInstance().getDataSource().saveTown(this); } + @Override + public Map getObjectDataMap() throws ObjectSaveException { + try { + Map twn_hm = new HashMap<>(); + twn_hm.put("name", getName()); + twn_hm.put("mayor", hasMayor() ? getMayor().getUUID() : ""); + twn_hm.put("mayorName", hasMayor() ? getMayor().getName() : ""); + twn_hm.put("nation", hasNation() ? getNation().getUUID() : ""); + twn_hm.put("nationName", hasNation() ? getNation().getName() : ""); + twn_hm.put("townBoard", getBoard()); + twn_hm.put("tag", getTag()); + twn_hm.put("founder", getFounder()); + twn_hm.put("protectionStatus", getPermissions().toString().replaceAll(",", "#")); + twn_hm.put("bonus", getBonusBlocks()); + twn_hm.put("purchased", getPurchasedBlocks()); + twn_hm.put("taxpercent", isTaxPercentage()); + twn_hm.put("maxPercentTaxAmount", getMaxPercentTaxAmount()); + twn_hm.put("taxes", getTaxes()); + twn_hm.put("hasUpkeep", hasUpkeep()); + twn_hm.put("plotPrice", getPlotPrice()); + twn_hm.put("plotTax", getPlotTax()); + twn_hm.put("commercialPlotPrice", getCommercialPlotPrice()); + twn_hm.put("commercialPlotTax", getCommercialPlotTax()); + twn_hm.put("embassyPlotPrice", getEmbassyPlotPrice()); + twn_hm.put("embassyPlotTax", getEmbassyPlotTax()); + twn_hm.put("open", isOpen()); + twn_hm.put("public", isPublic()); + twn_hm.put("adminEnabledMobs", isAdminEnabledMobs()); + twn_hm.put("adminDisabledPvP", isAdminDisabledPVP()); + twn_hm.put("adminEnabledPvP", isAdminEnabledPVP()); + twn_hm.put("allowedToWar", isAllowedToWar()); + twn_hm.put("homeblock", hasHomeBlock() ? getTownBlockForSaving(getHomeBlock()) : ""); + twn_hm.put("spawn", hasSpawn() ? parseLocationForSaving(getSpawn()) : ""); + StringBuilder outpostArray = new StringBuilder(); + if (hasOutpostSpawn()) + for (Location spawn : new ArrayList<>(getAllOutpostSpawns())) + outpostArray.append(parseLocationForSaving(spawn)).append(";"); + twn_hm.put("outpostSpawns", outpostArray.toString()); + twn_hm.put("outlaws", StringMgmt.join(getOutlaws(), "#")); + twn_hm.put("registered", getRegistered()); + twn_hm.put("spawnCost", getSpawnCost()); + twn_hm.put("mapColorHexCode", getMapColorHexCode()); + twn_hm.put("metadata", hasMeta() ? serializeMetadata(this) : ""); + twn_hm.put("conqueredDays", getConqueredDays()); + twn_hm.put("conquered", isConquered()); + twn_hm.put("ruined", isRuined()); + twn_hm.put("ruinedTime", getRuinedTime()); + twn_hm.put("neutral", isNeutral()); + twn_hm.put("debtBalance", getDebtBalance()); + twn_hm.put("joinedNationAt", getJoinedNationAt()); + if (getPrimaryJail() != null) + twn_hm.put("primaryJail", getPrimaryJail().getUUID()); + twn_hm.put("movedHomeBlockAt", getMovedHomeBlockAt()); + twn_hm.put("trustedResidents", StringMgmt.join(toUUIDList(getTrustedResidents()), "#")); + twn_hm.put("trustedTowns", StringMgmt.join(getTrustedTownsUUIDS(), "#")); + twn_hm.put("nationZoneOverride", getNationZoneOverride()); + twn_hm.put("nationZoneEnabled", isNationZoneEnabled()); + twn_hm.put("allies", StringMgmt.join(getAlliesUUIDs(), "#")); + twn_hm.put("enemies", StringMgmt.join(getEnemiesUUIDs(), "#")); + twn_hm.put("hasUnlimitedClaims", hasUnlimitedClaims()); + twn_hm.put("manualTownLevel", getManualTownLevel()); + twn_hm.put("forSale", isForSale()); + twn_hm.put("forSalePrice", getForSalePrice()); + twn_hm.put("forSaleTime", getForSaleTime()); + twn_hm.put("visibleOnTopLists", isVisibleOnTopLists()); + twn_hm.put("hasActiveWar", hasActiveWar()); + return twn_hm; + } catch (Exception e) { + throw new ObjectSaveException("An exception occurred when constructing data for town " + getName() + " (" + getUUID() + "), caused by: " + e.getMessage()); + } + } + + public boolean load(Map dataAsMap) { + String line = ""; + TownyUniverse universe = TownyUniverse.getInstance(); + try { + line = dataAsMap.get("mayor"); + if (line != null) { + try { + Resident res = universe.getResident(UUID.fromString(line)); + if (res == null) + throw new TownyException(); + forceSetMayor(res); + } catch (TownyException e1) { + if (getResidents().isEmpty()) + universe.getDataSource().deleteTown(this); + else + findNewMayor(); + + return true; + } + } + + line = dataAsMap.get("nation"); + if (hasData(line)) { + Nation nation = universe.getNation(UUID.fromString(line)); + if (nation != null) + setNation(nation, false); + } + setBoard(dataAsMap.getOrDefault("townBoard", TownySettings.getTownDefaultBoard())); + setTag(dataAsMap.getOrDefault("tag", "")); + line = dataAsMap.get("founder"); + if (hasData(line)) + setFounder(line); + setPermissions(dataAsMap.getOrDefault("protectionStatus", "")); + setBonusBlocks(getOrDefault(dataAsMap, "bonus", getOrDefault(dataAsMap, "bonusBlocks", 0))); // Old DB's used bonusBlocks + setPurchasedBlocks(getOrDefault(dataAsMap, "purchased", getOrDefault(dataAsMap, "purchasedBlocks", 0))); // Old DB's used bonusBlocks + setTaxPercentage(getOrDefault(dataAsMap, "taxpercent", TownySettings.getTownDefaultTaxPercentage())); + setMaxPercentTaxAmount(getOrDefault(dataAsMap, "maxPercentTaxAmount", TownySettings.getMaxTownTaxPercentAmount())); + setTaxes(getOrDefault(dataAsMap, "taxes", TownySettings.getTownDefaultTax())); + setHasUpkeep(getOrDefault(dataAsMap, "hasUpkeep", true)); + setPlotPrice(getOrDefault(dataAsMap, "plotPrice", 0.0)); + setPlotTax(getOrDefault(dataAsMap, "plotTax", TownySettings.getTownDefaultPlotTax())); + setCommercialPlotTax(getOrDefault(dataAsMap, "commercialPlotTax", TownySettings.getTownDefaultShopTax())); + setCommercialPlotPrice(getOrDefault(dataAsMap, "commercialPlotPrice", 0.0)); + setEmbassyPlotTax(getOrDefault(dataAsMap, "embassyPlotTax", TownySettings.getTownDefaultEmbassyTax())); + setEmbassyPlotPrice(getOrDefault(dataAsMap, "embassyPlotPrice", 0.0)); + setOpen(getOrDefault(dataAsMap, "open", TownySettings.getTownDefaultOpen())); + setPublic(getOrDefault(dataAsMap, "public", TownySettings.getTownDefaultPublic())); + setAdminEnabledMobs(getOrDefault(dataAsMap, "adminEnabledMobs", false)); + setAdminDisabledPVP(getOrDefault(dataAsMap, "adminDisabledPvP", false)); + setAdminEnabledPVP(getOrDefault(dataAsMap, "adminEnabledPvP", false)); + setAllowedToWar(getOrDefault(dataAsMap, "allowedToWar", TownySettings.getTownDefaultAllowedToWar())); + line = dataAsMap.get("homeBlock"); + if (line != null) { + try { + setHomeBlock(parseTownBlockFromDB(line)); + } catch (NumberFormatException e) { + TownyMessaging.sendErrorMsg(Translation.of("flatfile_err_homeblock_load_invalid_location", getName())); + } catch (NotRegisteredException e) { + TownyMessaging.sendErrorMsg(Translation.of("flatfile_err_homeblock_load_invalid_townblock", getName())); + } + } + + line = dataAsMap.get("spawn"); + if (hasData(line)) { + Location loc = parseSpawnLocationFromDB(line); + if (loc != null) + setSpawn(loc); + } + line = dataAsMap.get("outpostspawns"); + if (hasData(line)) { + String[] outposts = line.split(";"); + for (String spawn : outposts) { + Location loc = parseSpawnLocationFromDB(spawn); + if (loc != null) + forceAddOutpostSpawn(Position.ofLocation(loc)); + } + } + line = dataAsMap.get("outlaws"); + if (hasData(line)) + loadOutlaws(getResidentsFromDB(line)); + setRegistered(getOrDefault(dataAsMap, "registered", 0l)); + setSpawnCost(getOrDefault(dataAsMap, "spawnCost", TownySettings.getSpawnTravelCost())); + setMapColorHexCode(dataAsMap.getOrDefault("mapColorHexCode", MapUtil.generateRandomTownColourAsHexCode())); + setConqueredDays(getOrDefault(dataAsMap, "conqueredDays", 0)); + setConquered(getOrDefault(dataAsMap, "conquered", false)); + setRuined(getOrDefault(dataAsMap, "ruined", false)); + setRuinedTime(getOrDefault(dataAsMap, "ruinedTime", 0l)); + setNeutral(getOrDefault(dataAsMap, "neutral", TownySettings.getTownDefaultNeutral())); + setDebtBalance(getOrDefault(dataAsMap, "debtBalance", 0.0)); + setJoinedNationAt(getOrDefault(dataAsMap, "joinedNationAt", 0l)); + line = dataAsMap.get("primaryJail"); + if (hasData(line)) { + UUID jailUUID = UUID.fromString(line); + if (universe.hasJail(jailUUID)) + setPrimaryJail(universe.getJail(jailUUID)); + } + setMovedHomeBlockAt(getOrDefault(dataAsMap, "movedHomeBlockAt", 0l)); + line = dataAsMap.get("trustedResidents"); + if (hasData(line)) + getResidentsFromDB(line).stream().forEach(this::addTrustedResident); + line = dataAsMap.get("trustedTowns"); + if (hasData(line)) + getTownsFromDB(line).stream().forEach(this::addTrustedTown); + setNationZoneOverride(getOrDefault(dataAsMap, "nationZoneOverride", 0)); + setNationZoneEnabled(getOrDefault(dataAsMap, "nationZoneEnabled", false)); + line = dataAsMap.get("allies"); + if (hasData(line)) + loadAllies(TownyAPI.getInstance().getTowns(toUUIDArray(line.split(getSplitter(line))))); + line = dataAsMap.get("enemies"); + if (hasData(line)) + loadEnemies(TownyAPI.getInstance().getTowns(toUUIDArray(line.split(getSplitter(line))))); + setHasUnlimitedClaims(getOrDefault(dataAsMap, "hasUnlimitedClaims", false)); + setManualTownLevel(getOrDefault(dataAsMap, "manualTownLevel", -1)); + setForSale(getOrDefault(dataAsMap, "forSale", false)); + setForSalePrice(getOrDefault(dataAsMap, "forSalePrice", 0.0)); + setForSaleTime(getOrDefault(dataAsMap, "forSaleTime", 0l)); + setVisibleOnTopLists(getOrDefault(dataAsMap, "visibleOnTopLists", true)); + setAllowedToWar(getOrDefault(dataAsMap, "hasActiveWar", false)); + line = dataAsMap.get("metadata"); + if (hasData(line)) + MetadataLoader.getInstance().deserializeMetadata(this, line.trim()); + + try { + universe.registerTown(this); + } catch (AlreadyRegisteredException ignored) {} + if (exists()) + save(); + + } catch (Exception e) { + Towny.getPlugin().getLogger().log(Level.WARNING, Translation.of("flatfile_err_reading_town_file_at_line", getName(), line, getUUID().toString()), e); + return false; + } + return true; + } + public void saveTownBlocks() { townBlocks.values().stream().forEach(tb -> tb.save()); } diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/object/TownBlock.java b/Towny/src/main/java/com/palmergames/bukkit/towny/object/TownBlock.java index f532c455da4..f30c71164ee 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/object/TownBlock.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/object/TownBlock.java @@ -1,5 +1,7 @@ package com.palmergames.bukkit.towny.object; +import com.google.gson.Gson; +import com.palmergames.bukkit.towny.Towny; import com.palmergames.bukkit.towny.TownyAPI; import com.palmergames.bukkit.towny.TownyMessaging; import com.palmergames.bukkit.towny.TownySettings; @@ -11,13 +13,16 @@ import com.palmergames.bukkit.towny.event.plot.changeowner.PlotUnclaimEvent; import com.palmergames.bukkit.towny.exceptions.AlreadyRegisteredException; import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; +import com.palmergames.bukkit.towny.exceptions.ObjectSaveException; import com.palmergames.bukkit.towny.exceptions.TownyException; import com.palmergames.bukkit.towny.object.jail.Jail; import com.palmergames.bukkit.towny.object.metadata.CustomDataField; +import com.palmergames.bukkit.towny.object.metadata.MetadataLoader; import com.palmergames.bukkit.towny.tasks.CooldownTimerTask; import com.palmergames.bukkit.towny.tasks.CooldownTimerTask.CooldownType; import com.palmergames.bukkit.towny.utils.JailUtil; import com.palmergames.bukkit.util.BukkitTools; +import com.palmergames.util.StringMgmt; import com.palmergames.util.TimeTools; import org.jetbrains.annotations.ApiStatus; @@ -25,6 +30,7 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; @@ -32,6 +38,8 @@ import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.UUID; +import java.util.logging.Level; public class TownBlock extends TownyObject { @@ -564,6 +572,162 @@ public void save() { TownyUniverse.getInstance().getDataSource().saveTownBlock(this); } + @Override + public Map getObjectDataMap() throws ObjectSaveException { + try { + Map tb_hm = new HashMap<>(); + tb_hm.put("world", getWorld().getUUID()); + tb_hm.put("x", getX()); + tb_hm.put("z", getZ()); + tb_hm.put("name", getName()); + tb_hm.put("price", getPlotPrice()); + tb_hm.put("taxed", isTaxed()); + tb_hm.put("town", getTown().getUUID()); + tb_hm.put("townName", getTown().getName()); + tb_hm.put("resident", (hasResident()) ? getResidentOrNull().getUUID() : ""); + tb_hm.put("residentName", (hasResident()) ? getResidentOrNull().getName() : ""); + tb_hm.put("typeName", getTypeName()); + tb_hm.put("outpost", isOutpost()); + tb_hm.put("permissions", isChanged() ? getPermissions().toString().replaceAll(",", "#") : ""); + tb_hm.put("changed", isChanged()); + tb_hm.put("metadata", hasMeta() ? serializeMetadata(this) : ""); + tb_hm.put("groupID", hasPlotObjectGroup() ? getPlotObjectGroup().getUUID().toString() : ""); + tb_hm.put("districtID", hasDistrict() ? getDistrict().getUUID().toString() : ""); + tb_hm.put("claimedAt", getClaimedAt()); + tb_hm.put("trustedResidents", StringMgmt.join(toUUIDList(getTrustedResidents()), "#")); + Map stringMap = new HashMap<>(); + for (Map.Entry entry : getPermissionOverrides().entrySet()) + stringMap.put(entry.getKey().getUUID().toString(), entry.getValue().toString()); + tb_hm.put("customPermissionData", new Gson().toJson(stringMap)); + tb_hm.put("minTownMembershipDays", getMinTownMembershipDays()); + tb_hm.put("maxTownMembershipDays", getMaxTownMembershipDays()); + + + return tb_hm; + } catch (Exception e) { + throw new ObjectSaveException("An exception occurred when constructing data for townblock " + getName() + " (" + toString() + "), caused by: " + e.getMessage()); + } + } + + public boolean load(Map townBlockAsMap) { + String line = ""; + boolean save = false; + TownyUniverse universe = TownyUniverse.getInstance(); + try { + Town town = universe.getTown(UUID.fromString(townBlockAsMap.get("town"))); + if (town == null) { + TownyMessaging.sendErrorMsg("TownBlock file contains unregistered Town: " + townBlockAsMap.get("town") + + ", deleting " + getWorld().getName() + "," + getX() + "," + + getZ()); + universe.removeTownBlock(this); + universe.getDataSource().deleteTownBlock(this); + return true; + } + setTown(town, false); + try { + town.addTownBlock(this); + TownyWorld townyWorld = getWorld(); + if (townyWorld != null && !townyWorld.hasTown(town)) + townyWorld.addTown(town); + } catch (AlreadyRegisteredException ignored) {} + + line = townBlockAsMap.get("resident"); + if (hasData(line)) { + Resident resident = universe.getResident(UUID.fromString(line)); + if (resident != null) + setResident(resident, false); + else { + TownyMessaging.sendErrorMsg(String.format( + "Error fetching resident '%s' for townblock '%s'!", + line.trim(), toString())); + setResident(null); + save = true; + } + } + + setName(townBlockAsMap.getOrDefault("name", "")); + setType(TownBlockTypeHandler.getTypeInternal(townBlockAsMap.getOrDefault("typeName", "default"))); + setOutpost(getOrDefault(townBlockAsMap, "outpost", false)); + + line = townBlockAsMap.get("price"); + if (hasData(line)) + setPlotPrice(Float.parseFloat(line.trim())); + line = townBlockAsMap.get("taxed"); + if (hasData(line)) + setTaxed(Boolean.valueOf(line)); + line = townBlockAsMap.get("permissions"); + if (hasData(line)) + setPermissions(line.trim().replaceAll("#", ",")); + line = townBlockAsMap.get("changed"); + if (hasData(line)) + setChanged(getOrDefault(townBlockAsMap, line, false)); + line = townBlockAsMap.get("claimedAt"); + if (hasData(line)) + setClaimedAt(getOrDefault(townBlockAsMap, "claimedAt", 0l)); + line = townBlockAsMap.get("minTownMembershipDays"); + if (hasData(line)) + setMinTownMembershipDays(Integer.valueOf(line)); + line = townBlockAsMap.get("maxTownMembershipDays"); + if (hasData(line)) + setMaxTownMembershipDays(Integer.valueOf(line)); + + line = townBlockAsMap.get("metadata"); + if (hasData(line)) + MetadataLoader.getInstance().deserializeMetadata(this, line.trim()); + + line = townBlockAsMap.get("groupID"); + if (hasData(line)) + try { + PlotGroup group = universe.getGroup(UUID.fromString(line.trim())); + if (group != null) { + setPlotObjectGroup(group); + if (group.getPermissions() == null && getPermissions() != null) + group.setPermissions(getPermissions()); + if (hasResident()) + group.setResident(getResidentOrNull()); + } + } catch (Exception ignored) {} + + line = townBlockAsMap.get("districtID"); + if (hasData(line)) + try { + District district = universe.getDistrict(UUID.fromString(line.trim())); + if (district != null) { + setDistrict(district); + } else { + removeDistrict(); + } + } catch (Exception ignored) {} + + line = townBlockAsMap.get("trustedResidents"); + if (hasData(line) && getTrustedResidents().isEmpty()) { + addTrustedResidents(TownyAPI.getInstance().getResidents(toUUIDArray(line.split(getSplitter(line))))); + if (hasPlotObjectGroup() && getPlotObjectGroup().getTrustedResidents().isEmpty() && getTrustedResidents().size() > 0) + getPlotObjectGroup().setTrustedResidents(getTrustedResidents()); + } + + line = townBlockAsMap.get("customPermissionData"); + if (hasData(line) && getPermissionOverrides().isEmpty()) { + Map map = new Gson().fromJson(line, Map.class); + + for (Map.Entry entry : map.entrySet()) { + Resident resident = universe.getResident(UUID.fromString(entry.getKey())); + if (resident != null) + getPermissionOverrides().put(resident, new PermissionData(entry.getValue())); + } + + if (hasPlotObjectGroup() && getPlotObjectGroup().getPermissionOverrides().isEmpty() && getPermissionOverrides().size() > 0) + getPlotObjectGroup().setPermissionOverrides(getPermissionOverrides()); + } + if (save && exists()) + save(); + } catch (Exception e) { + Towny.getPlugin().getLogger().log(Level.WARNING, Translation.of("flatfile_err_exception_reading_townblock_file_at_line", toString(), line), e); + return false; + } + return true; + } + public long getClaimedAt() { return claimedAt; } diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/object/TownyObject.java b/Towny/src/main/java/com/palmergames/bukkit/towny/object/TownyObject.java index 0a7a5d3823f..51f0aeed948 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/object/TownyObject.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/object/TownyObject.java @@ -16,7 +16,7 @@ import java.util.List; import java.util.Map; -public abstract class TownyObject implements Nameable, Savable { +public abstract class TownyObject extends Loadable implements Nameable, Savable { private String name; private Map> metadata = null; diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/object/TownyWorld.java b/Towny/src/main/java/com/palmergames/bukkit/towny/object/TownyWorld.java index 9315e3d7152..5a69a4223a9 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/object/TownyWorld.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/object/TownyWorld.java @@ -1,11 +1,14 @@ package com.palmergames.bukkit.towny.object; +import com.palmergames.bukkit.towny.Towny; import com.palmergames.bukkit.towny.TownySettings; import com.palmergames.bukkit.towny.TownyUniverse; import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; +import com.palmergames.bukkit.towny.exceptions.ObjectSaveException; import com.palmergames.bukkit.towny.exceptions.TownyException; import com.palmergames.bukkit.towny.object.TownyPermission.ActionType; import com.palmergames.bukkit.towny.object.metadata.CustomDataField; +import com.palmergames.bukkit.towny.object.metadata.MetadataLoader; import com.palmergames.util.MathUtil; import com.palmergames.util.StringMgmt; @@ -31,6 +34,7 @@ import java.util.Set; import java.util.UUID; import java.util.function.UnaryOperator; +import java.util.logging.Level; import java.util.stream.Collectors; public class TownyWorld extends TownyObject { @@ -1059,6 +1063,153 @@ public void save() { TownyUniverse.getInstance().getDataSource().saveWorld(this); } + + @Override + public Map getObjectDataMap() throws ObjectSaveException { + try { + Map world_hm = new HashMap<>(); + world_hm.put("name", getName()); + world_hm.put("claimable", isClaimable()); + world_hm.put("pvp", isPVP()); + world_hm.put("forcepvp", isForcePVP()); + world_hm.put("forcetownmobs", isForceTownMobs()); + world_hm.put("friendlyFire", isFriendlyFireEnabled()); + world_hm.put("worldmobs", hasWorldMobs()); + world_hm.put("wildernessmobs", hasWildernessMobs()); + world_hm.put("firespread", isFire()); + world_hm.put("forcefirespread", isForceFire()); + world_hm.put("explosions", isExpl()); + world_hm.put("forceexplosions", isForceExpl()); + world_hm.put("endermanprotect", isEndermanProtect()); + world_hm.put("disablecreaturetrample", isDisableCreatureTrample()); + world_hm.put("unclaimedZoneBuild", getUnclaimedZoneBuild()); + world_hm.put("unclaimedZoneDestroy", getUnclaimedZoneDestroy()); + world_hm.put("unclaimedZoneSwitch", getUnclaimedZoneSwitch()); + world_hm.put("unclaimedZoneItemUse", getUnclaimedZoneItemUse()); + if (getUnclaimedZoneName() != null) + world_hm.put("unclaimedZoneName", getUnclaimedZoneName()); + + // Unclaimed Zone Ignore Ids + if (getUnclaimedZoneIgnoreMaterials() != null) + world_hm.put("unclaimedZoneIgnoreIds", StringMgmt.join(getUnclaimedZoneIgnoreMaterials(), "#")); + + // Using PlotManagement Delete + world_hm.put("usingPlotManagementDelete", isUsingPlotManagementDelete()); + // Plot Management Delete Ids + if (getPlotManagementDeleteIds() != null) + world_hm.put("plotManagementDeleteIds", StringMgmt.join(getPlotManagementDeleteIds(), "#")); + + // Deleting EntityTypes from Townblocks on Unclaim. + world_hm.put("isDeletingEntitiesOnUnclaim", isDeletingEntitiesOnUnclaim()); + if (getUnclaimDeleteEntityTypes() != null) + world_hm.put("unclaimDeleteEntityTypes", StringMgmt.join(getUnclaimDeleteEntityTypes(), "#")); + + + // Using PlotManagement Mayor Delete + world_hm.put("usingPlotManagementMayorDelete", isUsingPlotManagementMayorDelete()); + // Plot Management Mayor Delete + if (getPlotManagementMayorDelete() != null) + world_hm.put("plotManagementMayorDelete", StringMgmt.join(getPlotManagementMayorDelete(), "#")); + + // Using PlotManagement Revert + world_hm.put("usingPlotManagementRevert", isUsingPlotManagementRevert()); + + // Plot Management Ignore Ids + if (getPlotManagementIgnoreIds() != null) + world_hm.put("plotManagementIgnoreIds", StringMgmt.join(getPlotManagementIgnoreIds(), "#")); + + world_hm.put("revertOnUnclaimWhitelistMaterials", StringMgmt.join(getRevertOnUnclaimWhitelistMaterials(), "#")); + + // Using PlotManagement Wild Regen + world_hm.put("usingPlotManagementWildRegen", isUsingPlotManagementWildEntityRevert()); + + // Wilderness Explosion Protection entities + if (getPlotManagementWildRevertEntities() != null) + world_hm.put("PlotManagementWildRegenEntities", StringMgmt.join(getPlotManagementWildRevertEntities(), "#")); + + // Wilderness Explosion Protection Block Whitelist + if (getPlotManagementWildRevertBlockWhitelist() != null) + world_hm.put("PlotManagementWildRegenBlockWhitelist", StringMgmt.join(getPlotManagementWildRevertBlockWhitelist(), "#")); + + world_hm.put("wildRegenBlocksToNotOverwrite", StringMgmt.join(getWildRevertMaterialsToNotOverwrite(), "#")); + + // Using PlotManagement Wild Regen Delay + world_hm.put("plotManagementWildRegenSpeed", getPlotManagementWildRevertDelay()); + + // Using PlotManagement Wild Block Regen + world_hm.put("usingPlotManagementWildRegenBlocks", isUsingPlotManagementWildBlockRevert()); + + // Wilderness Explosion Protection blocks + if (getPlotManagementWildRevertBlocks() != null) + world_hm.put("PlotManagementWildRegenBlocks", StringMgmt.join(getPlotManagementWildRevertBlocks(), "#")); + + world_hm.put("usingTowny", isUsingTowny()); + world_hm.put("warAllowed", isWarAllowed()); + world_hm.put("jailing", isJailingEnabled()); + world_hm.put("metadata", hasMeta() ? serializeMetadata(this) : ""); + + return world_hm; + + } catch (Exception e) { + throw new ObjectSaveException("An exception occurred when constructing data for world " + getName() + " (" + getUUID() + "), caused by: " + e.getMessage()); + } + } + + public boolean load(Map worldAsMap) { + String line = ""; + try { + setClaimable(getOrDefault(worldAsMap,"claimable", true)); + setPVP(getOrDefault(worldAsMap, "pvp", TownySettings.isPvP())); + setForcePVP(getOrDefault(worldAsMap, "forcepvp", TownySettings.isForcingPvP())); + setForceTownMobs(getOrDefault(worldAsMap, "forcetownmobs", TownySettings.isForcingMonsters())); + setFriendlyFire(getOrDefault(worldAsMap, "friendlyFire", TownySettings.isFriendlyFireEnabled())); + setWorldMobs(getOrDefault(worldAsMap, "worldmobs", TownySettings.isWorldMonstersOn())); + setWildernessMobs(getOrDefault(worldAsMap, "wildernessmobs", TownySettings.isWildernessMonstersOn())); + setFire(getOrDefault(worldAsMap, "firespread", TownySettings.isFire())); + setForceFire(getOrDefault(worldAsMap, "forcefirespread", TownySettings.isForcingFire())); + setExpl(getOrDefault(worldAsMap, "explosions", TownySettings.isExplosions())); + setForceExpl(getOrDefault(worldAsMap, "forceexplosions", TownySettings.isForcingExplosions())); + setEndermanProtect(getOrDefault(worldAsMap, "endermanprotect", TownySettings.getEndermanProtect())); + setDisableCreatureTrample(getOrDefault(worldAsMap, "disablecreaturetrample", TownySettings.isCreatureTramplingCropsDisabled())); + setUnclaimedZoneBuild(getOrDefault(worldAsMap, "unclaimedZoneBuild", TownySettings.getUnclaimedZoneBuildRights())); + setUnclaimedZoneDestroy(getOrDefault(worldAsMap, "unclaimedZoneDestroy", TownySettings.getUnclaimedZoneDestroyRights())); + setUnclaimedZoneSwitch(getOrDefault(worldAsMap, "unclaimedZoneSwitch", TownySettings.getUnclaimedZoneSwitchRights())); + setUnclaimedZoneItemUse(getOrDefault(worldAsMap, "unclaimedZoneItemUse", TownySettings.getUnclaimedZoneItemUseRights())); + setUnclaimedZoneName(worldAsMap.getOrDefault("unclaimedZoneName", TownySettings.getUnclaimedZoneName())); + setUnclaimedZoneIgnore(toList(worldAsMap.get("unclaimedZoneIgnoreIds"))); + setUsingPlotManagementDelete(getOrDefault(worldAsMap, "usingPlotManagementDelete", TownySettings.isUsingPlotManagementDelete())); + setPlotManagementDeleteIds(toList(worldAsMap.get("plotManagementDeleteIds"))); + setDeletingEntitiesOnUnclaim(getOrDefault(worldAsMap, "isDeletingEntitiesOnUnclaim", TownySettings.isDeletingEntitiesOnUnclaim())); + setUnclaimDeleteEntityTypes(toList(worldAsMap.get("unclaimDeleteEntityTypes"))); + setUsingPlotManagementMayorDelete(getOrDefault(worldAsMap, "usingPlotManagementMayorDelete", TownySettings.isUsingPlotManagementMayorDelete())); + setPlotManagementMayorDelete(toList(worldAsMap.get("plotManagementMayorDelete"))); + setUsingPlotManagementRevert(getOrDefault(worldAsMap, "usingPlotManagementRevert", TownySettings.isUsingPlotManagementRevert())); + setPlotManagementIgnoreIds(toList(worldAsMap.get("plotManagementIgnoreIds"))); + setRevertOnUnclaimWhitelistMaterials(toList(worldAsMap.get("revertOnUnclaimWhitelistMaterials"))); + setUsingPlotManagementWildEntityRevert(getOrDefault(worldAsMap, "usingPlotManagementWildRegen", TownySettings.isUsingPlotManagementWildEntityRegen())); + setPlotManagementWildRevertEntities(toList(worldAsMap.get("PlotManagementWildRegenEntities"))); + setPlotManagementWildRevertBlockWhitelist(toList(worldAsMap.get("PlotManagementWildRegenBlockWhitelist"))); + setWildRevertMaterialsToNotOverwrite(toList(worldAsMap.get("wildRegenBlocksToNotOverwrite"))); + setPlotManagementWildRevertDelay(getOrDefault(worldAsMap, "plotManagementWildRegenSpeed", TownySettings.getPlotManagementWildRegenDelay())); + setUsingPlotManagementWildBlockRevert(getOrDefault(worldAsMap, "usingPlotManagementWildRegenBlocks", TownySettings.isUsingPlotManagementWildBlockRegen())); + setPlotManagementWildRevertMaterials(toList(worldAsMap.get("PlotManagementWildRegenBlocks"))); + setUsingTowny(getOrDefault(worldAsMap, "usingTowny", TownySettings.isUsingTowny())); + setWarAllowed(getOrDefault(worldAsMap, "warAllowed", TownySettings.isWarAllowed())); + line = worldAsMap.get("metadata"); + if (hasData(line)) + MetadataLoader.getInstance().deserializeMetadata(this, line.trim()); + setJailingEnabled(getOrDefault(worldAsMap, "jailing", TownySettings.isWorldJailingEnabled())); + + TownyUniverse.getInstance().registerTownyWorld(this); + if (exists()) + save(); + } catch (Exception e) { + Towny.getPlugin().getLogger().log(Level.WARNING, Translation.of("flatfile_err_exception_reading_world_file_at_line", getName(), line, getUUID().toString()), e); + return false; + } + return true; + } + @ApiStatus.Internal @Override public boolean exists() { diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/object/jail/Jail.java b/Towny/src/main/java/com/palmergames/bukkit/towny/object/jail/Jail.java index bc155644066..3e17d33815e 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/object/jail/Jail.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/object/jail/Jail.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; @@ -10,19 +11,24 @@ import java.util.stream.Collectors; import com.google.common.collect.Lists; -import com.palmergames.bukkit.towny.object.Position; import org.bukkit.Location; +import com.palmergames.bukkit.towny.object.Loadable; +import com.palmergames.bukkit.towny.object.Position; import com.palmergames.bukkit.towny.object.Savable; import com.palmergames.bukkit.towny.object.SpawnPoint; import com.palmergames.bukkit.towny.object.Town; import com.palmergames.bukkit.towny.object.TownBlock; import com.palmergames.bukkit.towny.object.SpawnPointLocation; import com.palmergames.bukkit.towny.object.SpawnPoint.SpawnPointType; +import com.palmergames.bukkit.towny.TownyMessaging; import com.palmergames.bukkit.towny.TownyUniverse; +import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; +import com.palmergames.bukkit.towny.exceptions.ObjectSaveException; + import org.jetbrains.annotations.ApiStatus; -public class Jail implements Savable { +public class Jail extends Loadable implements Savable { private UUID uuid; private Town town; @@ -133,6 +139,60 @@ public void save() { TownyUniverse.getInstance().getDataSource().saveJail(this); } + @Override + public Map getObjectDataMap() throws ObjectSaveException { + try { + Map jail_hm = new HashMap<>(); + jail_hm.put("townBlock", getTownBlockForSaving(getTownBlock())); + + StringBuilder jailCellArray = new StringBuilder(); + if (hasCells()) + for (Location cell : new ArrayList<>(getJailCellLocations())) + jailCellArray.append(parseLocationForSaving(cell)).append(";"); + + jail_hm.put("spawns", jailCellArray); + + return jail_hm; + } catch (Exception e) { + throw new ObjectSaveException("An exception occurred when constructing data for jail " + getName() + " (" + getUUID() + "), caused by: " + e.getMessage()); + } + } + + public boolean load(Map jailAsMap) { + String line = ""; + line = jailAsMap.get("townblock"); + if (line != null) { + try { + TownBlock tb = parseTownBlockFromDB(line); + setTownBlock(tb); + setTown(tb.getTownOrNull()); + tb.setJail(this); + tb.getTown().addJail(this); + } catch (NumberFormatException | NotRegisteredException e) { + TownyMessaging.sendErrorMsg("Jail " + getUUID() + " tried to load invalid townblock " + line + " deleting "); + TownyUniverse.getInstance().getDataSource().removeJail(this); + TownyUniverse.getInstance().getDataSource().deleteJail(this); + return true; + } + } + line = jailAsMap.get("spawns"); + if (line != null) { + String[] jails = line.split(";"); + for (String spawn : jails) { + Location loc = parseSpawnLocationFromDB(spawn); + if (loc != null) + addJailCell(loc); + } + if (getJailCellLocations().isEmpty()) { + TownyMessaging.sendErrorMsg("Jail " + getUUID() + " loaded with zero spawns " + line + " deleting "); + TownyUniverse.getInstance().getDataSource().removeJail(this); + TownyUniverse.getInstance().getDataSource().deleteJail(this); + return true; + } + } + return true; + } + public boolean hasCells() { return !jailCellMap.isEmpty(); } diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/tasks/OnPlayerLogin.java b/Towny/src/main/java/com/palmergames/bukkit/towny/tasks/OnPlayerLogin.java index d8262c5475d..2f8a5f6fc11 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/tasks/OnPlayerLogin.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/tasks/OnPlayerLogin.java @@ -9,6 +9,7 @@ import com.palmergames.bukkit.towny.TownyUpdateChecker; import com.palmergames.bukkit.towny.event.resident.NewResidentEvent; import com.palmergames.bukkit.towny.exceptions.AlreadyRegisteredException; +import com.palmergames.bukkit.towny.exceptions.InvalidNameException; import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; import com.palmergames.bukkit.towny.object.Nation; import com.palmergames.bukkit.towny.object.Resident; @@ -166,7 +167,7 @@ private void checkForNameChangeSinceLastLogIn(Resident resident) { private Resident createNewResident(Resident resident) { try { - resident = universe.getDataSource().newResident(player.getName(), player.getUniqueId()); + universe.newResident(player.getUniqueId(), player.getName()); resident.setRegistered(System.currentTimeMillis()); final Resident finalResident = resident; @@ -183,8 +184,9 @@ private Resident createNewResident(Resident resident) { resident.save(); plugin.getScheduler().run(player, () -> BukkitTools.fireEvent(new NewResidentEvent(finalResident))); - } catch (NotRegisteredException e) { + } catch (InvalidNameException e) { plugin.getLogger().log(Level.WARNING, "Could not register resident '" + player.getName() + "' (" + player.getUniqueId() + ") due to an error, Towny features might be limited for this player until it is resolved", e); + TownyMessaging.sendErrorMsg(player, e.getMessage() + " You have not been registered correctly with Towny!"); } catch (AlreadyRegisteredException ignored) {} return resident; @@ -214,11 +216,7 @@ private void loginExistingResident(Resident resident) { if (!resident.hasUUID()) { resident.setUUID(player.getUniqueId()); - try { - TownyUniverse.getInstance().registerResidentUUID(resident); - } catch (AlreadyRegisteredException e) { - plugin.getLogger().log(Level.WARNING, "uuid for resident " + resident.getName() + " was already registered! (" + player.getUniqueId() + ")", e); - } + TownyUniverse.getInstance().registerResidentUUID(resident); } resident.save(); }, 5); diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/utils/ResidentUtil.java b/Towny/src/main/java/com/palmergames/bukkit/towny/utils/ResidentUtil.java index 423de0b4a0b..d801bc4fd6e 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/utils/ResidentUtil.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/utils/ResidentUtil.java @@ -253,7 +253,8 @@ public static Resident createAndGetNPCResident() { try { String name = nextNpcName(); final UUID npcUUID = JavaUtil.changeUUIDVersion(UUID.randomUUID(), 2); - Resident npc = TownyUniverse.getInstance().getDataSource().newResident(name, npcUUID); + TownyUniverse.getInstance().newResident(npcUUID, name); + Resident npc = TownyUniverse.getInstance().getResident(npcUUID); npc.setRegistered(System.currentTimeMillis()); npc.setLastOnline(0); npc.setNPC(true); diff --git a/Towny/src/main/java/com/palmergames/util/FileMgmt.java b/Towny/src/main/java/com/palmergames/util/FileMgmt.java index 973555bf437..91827c6972e 100644 --- a/Towny/src/main/java/com/palmergames/util/FileMgmt.java +++ b/Towny/src/main/java/com/palmergames/util/FileMgmt.java @@ -10,6 +10,7 @@ import org.jetbrains.annotations.NotNull; import java.io.BufferedReader; +import java.io.BufferedWriter; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; @@ -25,6 +26,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.Map; import java.util.TreeSet; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; @@ -149,6 +151,27 @@ public static void copyDirectory(File sourceLocation, File targetLocation) throw } } + /** + * Write a map to a file, terminating each line with a system specific new line. + * + * @param source Map to write + * @param targetLocation Target location on the filesystem + * @throws IOException if an IO exception occurs while writing to the file + */ + public static void mapToFile(Map source, Path targetLocation) throws IOException { + try { + writeLock.lock(); + try (BufferedWriter writer = Files.newBufferedWriter(targetLocation)) { + for (Map.Entry entry : source.entrySet()) { + writer.write(entry.getKey() + "=" + entry.getValue()); + writer.newLine(); + } + } + } finally { + writeLock.unlock(); + } + } + /** * Write a list to a file, terminating each line with a system specific new line. *