diff --git a/src/engine/gameManager/BuildingManager.java b/src/engine/gameManager/BuildingManager.java index 8907339a..6292c457 100644 --- a/src/engine/gameManager/BuildingManager.java +++ b/src/engine/gameManager/BuildingManager.java @@ -798,7 +798,7 @@ public enum BuildingManager { // Attempt to write to database or delete the building // if we are destroying it. - if (rank == -1) + if (rank < 0) success = DbManager.BuildingQueries.DELETE_FROM_DATABASE(building); else success = DbManager.BuildingQueries.updateBuildingRank(building, rank); diff --git a/src/engine/mbEnums.java b/src/engine/mbEnums.java index bf2fca29..bedcc087 100644 --- a/src/engine/mbEnums.java +++ b/src/engine/mbEnums.java @@ -2732,7 +2732,7 @@ public class mbEnums { DIAMOND(1580010, 1540225085, -1730704107, 2000, 20), GALVOR(1580017, -1683992404, -1596311545, 2000, 5), IRON(1580002, -1673518119, 2504297, 2000, 20), - LUMBER(1580004, 1628412684, -1603256692, 10000, 100), + LUMBER(1580004, -1628412684, -1603256692, 10000, 100), MANDRAKE(1580007, 1519910613, 1191391799, 1000, 10), MITHRIL(1580021, 626743397, -1761257186, 500, 5), OAK(1580005, -1653034775, 74767, 3000, 30), diff --git a/src/engine/objects/Building.java b/src/engine/objects/Building.java index 5367c8f7..0a356546 100644 --- a/src/engine/objects/Building.java +++ b/src/engine/objects/Building.java @@ -561,7 +561,7 @@ public class Building extends AbstractWorldObject { BuildingManager.setRank(barracksBuilding, -1); } - // If the tree is R8 and deranking, we need to update it's + // If the tree is R8 and deranking, we need to update the // mesh along with buildings losing their health bonus if (this.rank == 8) { diff --git a/src/engine/objects/City.java b/src/engine/objects/City.java index 8f674de8..a9fae4b6 100644 --- a/src/engine/objects/City.java +++ b/src/engine/objects/City.java @@ -41,6 +41,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.ReentrantReadWriteLock; public class City extends AbstractWorldObject { @@ -80,6 +81,7 @@ public class City extends AbstractWorldObject { private String hash; public Warehouse warehouse; public Realm realm; + public AtomicBoolean isDestroyed = new AtomicBoolean(false); /** * ResultSet Constructor @@ -306,6 +308,21 @@ public class City extends AbstractWorldObject { if (city.parentZone == null) continue; + // Can't teleport to something without a tree + + if (city.getTOL() == null) + continue; + + // No abandoned cities + + if (city.getTOL().getGuild().isEmptyGuild()) + continue; + + // No destroyed cities + + if (city.getTOL().getRank() == -1) + continue; + //can't repledge to a guild you're already part of if (repledge && city.getGuild().equals(playerCharacter.guild)) @@ -1102,17 +1119,21 @@ public class City extends AbstractWorldObject { public final void destroy() { - Thread destroyCityThread = new Thread(new DestroyCityThread(this)); + if (this.isDestroyed.compareAndSet(false, true)) { - destroyCityThread.setName("destroyCity:" + this.getName()); - destroyCityThread.start(); + Thread destroyCityThread = new Thread(new DestroyCityThread(this)); + + destroyCityThread.setName("destroyCity:" + this.getParent().zoneName); + destroyCityThread.start(); + } else + Logger.error("Attempt to destroy destroyed city"); } public final void transfer(AbstractCharacter newOwner) { Thread transferCityThread = new Thread(new TransferCityThread(this, newOwner)); - transferCityThread.setName("TransferCity:" + this.getName()); + transferCityThread.setName("TransferCity:" + this.getParent().zoneName); transferCityThread.start(); } diff --git a/src/engine/objects/Mine.java b/src/engine/objects/Mine.java index dabfb557..553c1036 100644 --- a/src/engine/objects/Mine.java +++ b/src/engine/objects/Mine.java @@ -220,8 +220,7 @@ public class Mine extends AbstractGameObject { // Only inactive mines are returned. for (Mine mine : Mine.mineMap.keySet()) { - if (mine.owningGuild.getObjectUUID() == guildID && - mine.isActive == false) + if (mine.owningGuild.getObjectUUID() == guildID) mineList.add(mine); } return mineList; diff --git a/src/engine/workthreads/DestroyCityThread.java b/src/engine/workthreads/DestroyCityThread.java index 9c5b2050..77453c71 100644 --- a/src/engine/workthreads/DestroyCityThread.java +++ b/src/engine/workthreads/DestroyCityThread.java @@ -53,123 +53,117 @@ public class DestroyCityThread implements Runnable { // Member variable assignment - cityZone = city.getParent(); - newParent = cityZone.parent; - formerGuild = city.getTOL().getGuild(); + try { + cityZone = city.getParent(); + newParent = cityZone.parent; + formerGuild = city.getTOL().getGuild(); - // Former guild loses it's tree! + Logger.info("Destroy city thread started for: " + cityZone.zoneName); - if (DbManager.GuildQueries.SET_GUILD_OWNED_CITY(formerGuild.getObjectUUID(), 0)) { + // Former guild loses tree! - //Successful Update of guild + if (DbManager.GuildQueries.SET_GUILD_OWNED_CITY(formerGuild.getObjectUUID(), 0)) { - formerGuild.setGuildState(mbEnums.GuildState.Errant); - formerGuild.setNation(null); - formerGuild.setCityUUID(0); - GuildManager.updateAllGuildTags(formerGuild); - GuildManager.updateAllGuildBinds(formerGuild, null); - } + //Successful Update of guild + + formerGuild.setGuildState(mbEnums.GuildState.Errant); + formerGuild.setNation(null); + formerGuild.setCityUUID(0); + GuildManager.updateAllGuildTags(formerGuild); + GuildManager.updateAllGuildBinds(formerGuild, null); + } - // By losing the tree, the former owners lose all of their subguilds. + // By losing the tree, the former owners lose all of their subguilds. - if (!formerGuild.getSubGuildList().isEmpty()) { + if (!formerGuild.getSubGuildList().isEmpty()) { - subGuildList = new ArrayList<>(); + subGuildList = new ArrayList<>(); - subGuildList.addAll(formerGuild.getSubGuildList()); + subGuildList.addAll(formerGuild.getSubGuildList()); - for (Guild subGuild : subGuildList) { - formerGuild.removeSubGuild(subGuild); + for (Guild subGuild : subGuildList) { + formerGuild.removeSubGuild(subGuild); + } } - } - Building tol = null; + // Build list of buildings within this parent zone - // Build list of buildings within this parent zone + ArrayList destroySet = new ArrayList<>(); - for (Building cityBuilding : cityZone.zoneBuildingSet) { + for (Building cityBuilding : cityZone.zoneBuildingSet) { - // Sanity Check in case player deletes the building - // before this thread can get to it + // Sanity Check in case player deletes the building + // before this thread can get to it - if (cityBuilding == null) - continue; + if (cityBuilding == null) + continue; - // Do nothing with the banestone. It will be removed elsewhere + // Do nothing with the banestone. It will be removed elsewhere - if (cityBuilding.getBlueprint().getBuildingGroup().equals(mbEnums.BuildingGroup.BANESTONE)) - continue; + if (cityBuilding.getBlueprint().getBuildingGroup().equals(mbEnums.BuildingGroup.BANESTONE)) + continue; - // TOL is processed after all other structures in the city zone + // All buildings are moved to a location relative + // to their new parent zone - if (cityBuilding.getBlueprint().getBuildingGroup().equals(mbEnums.BuildingGroup.TOL)) { - tol = cityBuilding; - continue; - } + localCoords = ZoneManager.worldToLocal(cityBuilding.getLoc(), newParent); - // All buildings are moved to a location relative - // to their new parent zone + DbManager.BuildingQueries.MOVE_BUILDING(cityBuilding.getObjectUUID(), newParent.getObjectUUID(), localCoords.x, localCoords.y, localCoords.z); - localCoords = ZoneManager.worldToLocal(cityBuilding.getLoc(), newParent); + // All buildings are re-parented to a zone one node + // higher in the tree (continent) as we will be + // deleting the city zone very shortly. - DbManager.BuildingQueries.MOVE_BUILDING(cityBuilding.getObjectUUID(), newParent.getObjectUUID(), localCoords.x, localCoords.y, localCoords.z); + if (cityBuilding.getParentZoneID() != newParent.getParentZoneID()) + cityBuilding.setParentZone(newParent); - // All buildings are re-parented to a zone one node - // higher in the tree (continent) as we will be - // deleting the city zone very shortly. + // No longer a tree, no longer any protection contract! - if (cityBuilding.getParentZoneID() != newParent.getParentZoneID()) - cityBuilding.setParentZone(newParent); + cityBuilding.setProtectionState(mbEnums.ProtectionState.NONE); - // No longer a tree, no longer any protection contract! + // Remove warehouse entry if one exists. - cityBuilding.setProtectionState(mbEnums.ProtectionState.NONE); + if (cityBuilding.getBlueprint().getBuildingGroup() == mbEnums.BuildingGroup.WAREHOUSE) { + DbManager.WarehouseQueries.DELETE_WAREHOUSE(city.warehouse); + city.warehouse = null; + } - // Remove warehouse entry if one exists. + // Mark all auto protected buildings for destruction - if (cityBuilding.getBlueprint().getBuildingGroup() == mbEnums.BuildingGroup.WAREHOUSE) { - DbManager.WarehouseQueries.DELETE_WAREHOUSE(city.warehouse); - city.warehouse = null; + if ((cityBuilding.getBlueprint().getBuildingGroup() == mbEnums.BuildingGroup.BARRACK) || (cityBuilding.getBlueprint().isWallPiece()) || (cityBuilding.getBlueprint().getBuildingGroup() == mbEnums.BuildingGroup.SHRINE) || (cityBuilding.getBlueprint().getBuildingGroup() == mbEnums.BuildingGroup.TOL) || (cityBuilding.getBlueprint().getBuildingGroup() == mbEnums.BuildingGroup.SPIRE) || (cityBuilding.getBlueprint().getBuildingGroup() == mbEnums.BuildingGroup.WAREHOUSE)) + destroySet.add(cityBuilding); } - // Destroy all remaining city assets + // Destroy set of auto-protected buildings - if ((cityBuilding.getBlueprint().getBuildingGroup() == mbEnums.BuildingGroup.BARRACK) - || (cityBuilding.getBlueprint().isWallPiece()) - || (cityBuilding.getBlueprint().getBuildingGroup() == mbEnums.BuildingGroup.SHRINE) - || (cityBuilding.getBlueprint().getBuildingGroup() == mbEnums.BuildingGroup.TOL) - || (cityBuilding.getBlueprint().getBuildingGroup() == mbEnums.BuildingGroup.SPIRE) - || (cityBuilding.getBlueprint().getBuildingGroup() == mbEnums.BuildingGroup.WAREHOUSE)) { + for (Building building : destroySet) + if (building.getRank() != -1) + BuildingManager.setRank(building, -1); - if (cityBuilding.getRank() != -1) - BuildingManager.setRank(cityBuilding, -1); + if (city.realm != null) { + city.realm.removeCity(city.getObjectUUID()); + city.realm = null; } - } - - // Destroy the tol - if (tol != null) - BuildingManager.setRank(tol, -1); + // It's now safe to delete the city zone from the database + // which will cause a cascade delete of everything else - if (city.realm != null) - city.realm.removeCity(city.getObjectUUID()); + if (!DbManager.ZoneQueries.DELETE_ZONE(cityZone)) { + Logger.error("DestroyCityThread", "Database error when deleting city zone: " + cityZone.getObjectUUID()); + return; + } - // It's now safe to delete the city zone from the database - // which will cause a cascade delete of everything else + // Refresh the city for map requests + City.lastCityUpdate = System.currentTimeMillis(); - if (DbManager.ZoneQueries.DELETE_ZONE(cityZone) == false) { - Logger.error("DestroyCityThread", "Database error when deleting city zone: " + cityZone.getObjectUUID()); - return; + } catch (Exception e) { + Logger.error(e); } - // Refresh the city for map requests - - City.lastCityUpdate = System.currentTimeMillis(); - // Zone and city should vanish upon next reboot // if the codebase reaches here. - Logger.info(city.getParent().zoneName + " uuid:" + city.getObjectUUID() + "has been destroyed!"); + Logger.info(city.getParent().zoneName + " uuid: " + city.getObjectUUID() + " has been destroyed!"); } }