A => src/main/java/DBObjects/ConflictChange.java +99 -0
@@ 0,0 1,99 @@
+
+package DBObjects;
+
+import static DBObjects.CityDB.logger;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Represents a change in a conflict (usually a war) for a country.
+ * This has a goal of allowing the XML files to be auto-updated even as cities are
+ * added, with countries controlling the granularity of events.
+ * @author Andrew
+ */
+public class ConflictChange {
+
+ private final String countryName;
+ private final String conflictName;
+ private final int statusType; //-2 = total war, -1 = war, 0 = mid-level conflict, 1 = back to normal
+ private final int year;
+ private final int month;
+
+ private static final Map<String, List<ConflictChange>> conflictChangesByMonth = new HashMap<>();
+
+ private ConflictChange(String countryName, String conflictName, int statusType, int year, int month) {
+ this.countryName = countryName;
+ this.conflictName = conflictName;
+ this.statusType = statusType;
+ this.year = year;
+ this.month = month;
+ String key = year + "-" + month;
+ if (!conflictChangesByMonth.containsKey(key)) {
+ conflictChangesByMonth.put(key, new ArrayList<>());
+ }
+ conflictChangesByMonth.get(key).add(this);
+ }
+
+ public static void read(Connection conn) {
+ try {
+ PreparedStatement stmt = conn.prepareStatement(
+ "SELECT Country, Conflict, StartYear, StartMonth, EndYear, EndMonth, Type from CountryConflicts"
+ );
+ ResultSet rs = stmt.executeQuery();
+ while (rs.next()) {
+ String country = rs.getString(1);
+ String conflict = rs.getString(2);
+ int startYear = rs.getInt(3);
+ int startMonth = rs.getInt(4);
+ int endYear = rs.getInt(5);
+ int endMonth = rs.getInt(6);
+ int type = rs.getInt(7);
+ ConflictChange start = new ConflictChange(country, conflict, type, startYear, startMonth);
+ ConflictChange end = new ConflictChange(country, conflict, 1, endYear, endMonth);
+ }
+ }
+ catch(SQLException ex) {
+ logger.error("Unexpected SQL exception", ex);
+ }
+ }
+
+ public static List<ConflictChange> getConflictChangesByMonth(int year, int month) {
+ String key = year + "-" + month;
+ if (!conflictChangesByMonth.containsKey(key)) {
+ return new ArrayList<>();
+ }
+ else {
+ return conflictChangesByMonth.get(key);
+ }
+ }
+
+ public String getCountryName() {
+ return countryName;
+ }
+
+ public String getConflictName() {
+ return conflictName;
+ }
+
+ public int getStatusType() {
+ return statusType;
+ }
+
+ public int getYear() {
+ return year;
+ }
+
+ public int getMonth() {
+ return month;
+ }
+
+ public Map<String, List<ConflictChange>> getConflictChangesByMonth() {
+ return conflictChangesByMonth;
+ }
+}
M src/main/java/com/ajtjp/gearCity/Main.java +95 -0
@@ 3,6 3,7 @@ package com.ajtjp.gearCity;
import DBObjects.CalculatedObjects.CurrencyFigure;
import DBObjects.CityDB;
+import DBObjects.ConflictChange;
import DBObjects.CountryDB;
import DBObjects.ExchangeRates;
import DBObjects.RegionDB;
@@ 23,14 24,19 @@ import com.ajtjp.gearCity.CityInfoFile.X
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
+import java.util.Scanner;
import java.util.Set;
import java.util.stream.Collectors;
import javax.xml.parsers.DocumentBuilder;
@@ 81,6 87,7 @@ public class Main {
List<RegionalDemographicsDB> regionalDemographics = dbReader.getRegionalDemographics();
List<UrbanPopulationDB> urbanPopulation = dbReader.getUrbanPopulationDB();
ExchangeRates.readFromDatabase(dbReader.getConn());
+ ConflictChange.read(dbReader.getConn());
//Test our currency conversion
CurrencyFigure oneThousandNorwegianKroner = new CurrencyFigure(1900, 1000, "NOK");
@@ 153,6 160,9 @@ cityDBLoop: for (CityDB city : cities) {
ExportToCityFile("D:\\Gear City Mods\\Europe Expanded II\\Maps\\Europe Expanded II\\scripts\\City2020.xml", transformer, source);
}
+ //Update TurnEvents.xml
+ updateTurnEvents(cities);
+
//Copy things over
Process proc = Runtime.getRuntime().exec("D:\\Gear City Mods\\Europe Expanded II\\desktopCopy.bat", null, new File("D:/Gear City Mods/Europe Expanded II/"));
int result = proc.waitFor();
@@ 173,6 183,91 @@ cityDBLoop: for (CityDB city : cities) {
}
}
}
+
+ /**
+ * Updates the turn events file.
+ * This is not a proper XML parser. XML is not as convenient to build for as JSON, so rather than go to the work of parsing everything we need,
+ * I've just built a custom reader for the things we care about.
+ */
+ private static void updateTurnEvents(List<CityDB> cities) {
+ int year = 1899;
+ int month = 1900;
+ List<ConflictChange> changes = new ArrayList<>();
+ List<Integer> cityIDsExpected = new ArrayList<>();
+ Map<Integer, Integer> cityToStatusMap = new HashMap<>();
+ List<Integer> cityIDsFound = new ArrayList<>();
+ File tempOutput = new File("D:/Gear City Mods/Europe Expanded II/Maps/Europe Expanded II/Scripts/TurnEventsUpdated.xml");
+ try {
+ FileWriter fw = new FileWriter("D:/Gear City Mods/Europe Expanded II/Maps/Europe Expanded II/scripts/TurnEventsUpdated.xml");
+ File source = new File("D:/Gear City Mods/Europe Expanded II/Maps/Europe Expanded II/scripts/TurnEvents.xml");
+ if (!source.exists()) {
+ System.out.println(source + " does not exist");
+ }
+ Scanner scan = new Scanner(new File("D:/Gear City Mods/Europe Expanded II/Maps/Europe Expanded II/scripts/TurnEventsOrig.xml"));
+ while (scan.hasNextLine()) {
+ String nextLine = scan.nextLine();
+
+ int yearIndex = nextLine.indexOf("<year y");
+ if (yearIndex > -1) {
+ year = Integer.parseInt(nextLine.substring(yearIndex + 9, yearIndex + 13));
+ System.out.println("Updated turn events year to " + year);
+ if (year == 2019) {
+ System.out.println("debug");
+ }
+ }
+ int monthIndex = nextLine.indexOf("<turn t");
+ if (monthIndex > -1) {
+ boolean twoDigits = nextLine.length() == 21;
+ month = Integer.parseInt(nextLine.substring(monthIndex + 9, monthIndex + 9 + (twoDigits ? 2 : 1)));
+ System.out.println("Updated turn events month to " + month);
+ changes = ConflictChange.getConflictChangesByMonth(year, month);
+ if (changes.size() > 0) {
+ for (ConflictChange change : changes) {
+ for (CityDB city : cities) {
+ if (city.getCountry().getName().equals(change.getCountryName())) {
+ cityIDsExpected.add(city.getXmlID());
+ cityToStatusMap.put(city.getXmlID(), change.getStatusType());
+ }
+ }
+ }
+ }
+ }
+
+ if (cityIDsExpected.size() > 0 && nextLine.contains("<cityChange id")) {
+ int idIndex = nextLine.indexOf("id");
+ int endQuoteIndex = nextLine.indexOf("\"", idIndex + 4);
+ int foundId = Integer.parseInt(nextLine.substring(idIndex + 4, endQuoteIndex));
+ System.out.println("Found id " + foundId + " in " + year + "-" + month);
+ cityIDsFound.add(foundId);
+ }
+
+ if (nextLine.contains("</WorldEvts>") && cityIDsExpected.size() > 0) {
+ //Need to add lines for any city IDs not found
+ for (Integer idExpected : cityIDsExpected) {
+ if (!cityIDsFound.contains(idExpected)) {
+ //TODO: This isn't quite right yet. The government should not always be -1. We have to store that somewhere.
+ System.out.println("Adding city " + idExpected);
+ String lineToAdd = " <cityChange id=\"" + idExpected + "\" gov=\"" + cityToStatusMap.get(idExpected) + "\"/>\r\n";
+ fw.write(lineToAdd);
+ }
+ }
+
+ //Reset
+ cityIDsExpected.clear();
+ cityIDsFound.clear();
+ }
+
+ //If we are checking for events...
+
+ fw.write(nextLine + "\r\n");
+ }
+ fw.flush();
+ fw.close();
+ }
+ catch(IOException ex) {
+ System.err.println(ex.getMessage());
+ }
+ }
static void printCityGrowthStats(List<CityDB> cities, int year) {
List<CityDB> fastestGrowingCities = (List<CityDB>)cities.stream().sorted(new Comparator() {