diff --git a/odb/cities/placeholder.txt b/odb/cities/placeholder.txt new file mode 100644 index 00000000..e69de29b diff --git a/src/main/NGECore.java b/src/main/NGECore.java index 221cbc28..757f4d39 100644 --- a/src/main/NGECore.java +++ b/src/main/NGECore.java @@ -99,6 +99,7 @@ import services.object.ObjectId; import services.object.ObjectService; import services.object.UpdateService; import services.pet.MountService; +import services.playercities.PlayerCity; import services.playercities.PlayerCityService; import services.resources.HarvesterService; import services.resources.ResourceService; @@ -228,6 +229,7 @@ public class NGECore { private ObjectDatabase resourceHistoryODB; private ObjectDatabase swgObjectODB; private ObjectDatabase bountiesODB; + private ObjectDatabase cityODB; public static boolean PACKET_DEBUG = false; @@ -306,6 +308,7 @@ public class NGECore { resourceHistoryODB = new ObjectDatabase("resourcehistory", true, true, true, GalacticResource.class); auctionODB = new ObjectDatabase("auction", true, true, true, AuctionItem.class); bountiesODB = new ObjectDatabase("bounties", true, true, true, BountyListItem.class); + cityODB = new ObjectDatabase("cities", true, true, true, PlayerCity.class); // Services loginService = new LoginService(this); @@ -521,6 +524,7 @@ public class NGECore { equipmentService.loadBonusSets(); playerCityService.loadCityRankCaps(); + playerCityService.loadCities(); retroService.run(); didServerCrash = false; @@ -676,7 +680,11 @@ public class NGECore { public ObjectDatabase getAuctionODB() { return auctionODB; } - + + public ObjectDatabase getCityODB() { + return cityODB; + } + public int getActiveClients() { int connections = 0; for (Map.Entry c : clients.entrySet()) { @@ -784,6 +792,7 @@ public class NGECore { objectIdODB.close(); duplicateIdODB.close(); auctionODB.close(); + cityODB.close(); } public String getMotd() { diff --git a/src/resources/common/ProsePackage.java b/src/resources/common/ProsePackage.java index bdb10e5f..0d7b9dcc 100644 --- a/src/resources/common/ProsePackage.java +++ b/src/resources/common/ProsePackage.java @@ -221,4 +221,11 @@ public class ProsePackage implements Serializable { this.dfFloat = dfFloat; } + public void init() { + stf.init(null); + tuStf.init(null); + ttStf.init(null); + toStf.init(null); + } + } diff --git a/src/services/chat/ChatService.java b/src/services/chat/ChatService.java index 84835f18..95747297 100644 --- a/src/services/chat/ChatService.java +++ b/src/services/chat/ChatService.java @@ -350,7 +350,7 @@ public class ChatService implements INetworkDispatch { return; mail.setStatus(Mail.READ); - + mail.init(); sendPersistentMessage(client, mail); storePersistentMessage(mail); diff --git a/src/services/chat/Mail.java b/src/services/chat/Mail.java index dbb0c1f5..2cad7452 100644 --- a/src/services/chat/Mail.java +++ b/src/services/chat/Mail.java @@ -27,7 +27,7 @@ import java.util.List; import resources.common.OutOfBand; import resources.common.ProsePackage; - +import engine.resources.common.Stf; import com.sleepycat.persist.model.Entity; import com.sleepycat.persist.model.PrimaryKey; @@ -149,5 +149,9 @@ public class Mail implements Serializable { public void addProseAttachment(ProsePackage prose) { proseAttachments.add(prose); } + + public void init() { + proseAttachments.forEach(ProsePackage::init); + } } diff --git a/src/services/object/ObjectService.java b/src/services/object/ObjectService.java index 1577f502..96070041 100644 --- a/src/services/object/ObjectService.java +++ b/src/services/object/ObjectService.java @@ -165,6 +165,7 @@ public class ObjectService implements INetworkDispatch { core.bazaarService.saveAllItems(); core.housingService.saveBuildings(); core.harvesterService.saveHarvesters(); + core.playerCityService.saveAllCities(); core.closeODBs(); } }); diff --git a/src/services/playercities/PlayerCity.java b/src/services/playercities/PlayerCity.java index 948bb0bc..1ab1442b 100644 --- a/src/services/playercities/PlayerCity.java +++ b/src/services/playercities/PlayerCity.java @@ -26,7 +26,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; +import java.util.Map; import java.util.Vector; +import java.util.concurrent.ConcurrentHashMap; import net.engio.mbassy.listener.Handler; import resources.common.OutOfBand; @@ -129,8 +131,7 @@ public class PlayerCity implements Serializable { private Vector placedStructures = new Vector(); private Vector citizens = new Vector(); - private Vector electionCandidates = new Vector(); - private Vector electionVotes = new Vector(); + private Map electionList = new ConcurrentHashMap(); private Vector cityBanList = new Vector(); private Vector militiaList = new Vector(); private Vector foundersList = new Vector(); @@ -156,7 +157,7 @@ public class PlayerCity implements Serializable { area.getEventBus().subscribe(this); NGECore.getInstance().simulationService.addCollidable(area, area.getCenter().x, area.getCenter().z); } - + public void handleGrantZoning() { } @@ -173,9 +174,6 @@ public class PlayerCity implements Serializable { // ToDo: handle everything long winnerID = mayorID; mayorID = winnerID; - electionVotes.clear(); - electionCandidates.clear(); - electionCandidates.add(mayorID); setNextElectionDate(System.currentTimeMillis()+legislationPeriod); } @@ -271,10 +269,17 @@ public class PlayerCity implements Serializable { int newRank = getRank() + 1; setRank(newRank); sendCityExpandMail(); + addNewStructures(); fixupCitizens(); } + private void addNewStructures() { + NGECore core = NGECore.getInstance(); + List objects = core.simulationService.get(core.terrainService.getPlanetByID(planetId), area.getCenter().x, area.getCenter().x, 500); + objects.stream().filter(o -> o instanceof BuildingObject && o.getAttachment("structureOwner") != null && area.doesCollide(o)).map(SWGObject::getObjectID).forEach(this::addNewStructure); + } + // cleanup in case something went wrong public void fixupCitizens() { List residents = new ArrayList(); @@ -651,14 +656,6 @@ public class PlayerCity implements Serializable { this.nextElectionDate = nextElectionDate; } - public Vector getElectionCandidates() { - return electionCandidates; - } - - public void setElectionCandidates(Vector electionCandidates) { - this.electionCandidates = electionCandidates; - } - public long getNextCityUpdate() { return nextCityUpdate; } @@ -675,14 +672,6 @@ public class PlayerCity implements Serializable { this.cityBanList = cityBanList; } - public Vector getElectionVotes() { - return electionVotes; - } - - public void addToElectionVotes(byte vote) { - electionVotes.add(vote); - } - public void addToTreasury(int amountToAdd) { cityTreasury += amountToAdd; } @@ -691,11 +680,6 @@ public class PlayerCity implements Serializable { cityTreasury -= amountToDeduct; } - // Stalinesque method :D - public void setElectionVotes(Vector electionVotes) { - this.electionVotes = electionVotes; - } - public Point3D getCityCenterPosition() { return cityCenterPosition; } @@ -905,7 +889,7 @@ public class PlayerCity implements Serializable { actorMail.setTimeStamp((int) (new Date().getTime() / 1000)); actorMail.setSubject("@city/city:new_city_citizen_subject"); actorMail.setSenderName("City " + this.cityName); - actorMail.addProseAttachment(new ProsePackage("@city/city:new_city_citizen_body", "TT", newCitizen.getCustomName())); + actorMail.addProseAttachment(new ProsePackage("@city/city:new_city_citizen_body", "TO", newCitizen.getCustomName())); NGECore.getInstance().chatService.storePersistentMessage(actorMail); if (newCitizen.getClient()!=null) @@ -1220,5 +1204,13 @@ public class PlayerCity implements Serializable { this.planetId = planetId; } + public Map getElectionList() { + return electionList; + } + + public void setElectionList(Map electionList) { + this.electionList = electionList; + } + } diff --git a/src/services/playercities/PlayerCityService.java b/src/services/playercities/PlayerCityService.java index 3ceb0a69..75f2a1b8 100644 --- a/src/services/playercities/PlayerCityService.java +++ b/src/services/playercities/PlayerCityService.java @@ -41,6 +41,7 @@ import services.chat.Mail; import services.sui.SUIWindow; import services.sui.SUIWindow.SUICallback; import services.sui.SUIWindow.Trigger; +import engine.resources.database.ODBCursor; import engine.resources.objects.SWGObject; import engine.resources.scene.Planet; import engine.resources.scene.Point3D; @@ -75,6 +76,26 @@ public class PlayerCityService implements INetworkDispatch { cityRankCaps.put(planetName, caps); } + public void saveAllCities() { + playerCities.forEach(c -> core.objectService.persistObject(c.getCityID(), c, core.getCityODB())); + } + + public void loadCities() { + ODBCursor cursor = core.getCityODB().getCursor(); + while(cursor.hasNext()) { + PlayerCity city = (PlayerCity) cursor.next(); + if(city == null) + continue; + city.init(); + playerCities.add(city); + if(System.currentTimeMillis() < city.getNextCityUpdate()) + city.processCityUpdate(); + else + schedulePlayerCityUpdate(city, city.getNextCityUpdate() - System.currentTimeMillis()); + } + cursor.close(); + } + public boolean isRankCapped(Planet planet, int rank) { if(cityRankCaps.get(planet.getName()) == null) return true; @@ -141,10 +162,12 @@ public class PlayerCityService implements INetworkDispatch { PlayerCity playerCity = addNewPlayerCity(actor, cityHall); playerCity.setCityName(name); + playerCity.addNewStructure(cityHall.getObjectID()); PlayerCityService.this.schedulePlayerCityUpdate(playerCity, PlayerCity.newCityGraceSpan); cityHall.setAttachment("structureCity", playerCity.getCityID()); actor.setAttachment("residentCity", playerCity.getCityID()); core.housingService.declareResidency(actor, cityHall); + core.objectService.persistObject(playerCity.getCityID(), playerCity, core.getCityODB()); newCitySUI2((CreatureObject) owner, playerCity); } @@ -180,7 +203,7 @@ public class PlayerCityService implements INetworkDispatch { PlayerCity foundCity = null; synchronized(playerCities){ for (PlayerCity city : playerCities){ - int id = (int)citizen.getAttachment("residentCity"); + long id = (long)citizen.getAttachment("residentCity"); if (city.getCityID()==id){ foundCity = city; } @@ -374,6 +397,7 @@ public class PlayerCityService implements INetworkDispatch { } core.simulationService.removeCollidable(city.getArea(), city.getArea().getCenter().x, city.getArea().getCenter().z); playerCities.remove(city); + core.objectService.deletePersistentObject(city.getCityID(), core.getCityODB()); }