diff --git a/src/main/java/net/tfminecraft/simplefactions/Cache.java b/src/main/java/net/tfminecraft/simplefactions/Cache.java index b8f21dfd..d24bbbd0 100644 --- a/src/main/java/net/tfminecraft/simplefactions/Cache.java +++ b/src/main/java/net/tfminecraft/simplefactions/Cache.java @@ -174,16 +174,6 @@ public static boolean requireProvinces(org.bukkit.command.CommandSender sender) /** Share of a sea or rail delivery left in the provinces along the way. */ public static double supplyHubCorridorShare = 0.5; - public static double infrastructureFull = 20; - public static double infrastructureTarget = 0.75; - public static double infrastructureWildernessSpread = 0.25; - public static double infrastructureSpreadFloor = 0.5; - public static double infrastructureStation = 10; - public static double infrastructurePort = 10; - public static double infrastructureAirport = 5; - public static double infrastructureTrack = 10; - public static int infrastructureTrackRefreshSeconds = 300; - public static Map baseEffects = new HashMap<>(); public static Map tradeCarry = new HashMap<>(); diff --git a/src/main/java/net/tfminecraft/simplefactions/SimpleFactions.java b/src/main/java/net/tfminecraft/simplefactions/SimpleFactions.java index f4fd0ff0..e3c0f832 100644 --- a/src/main/java/net/tfminecraft/simplefactions/SimpleFactions.java +++ b/src/main/java/net/tfminecraft/simplefactions/SimpleFactions.java @@ -171,7 +171,8 @@ public class SimpleFactions extends JavaPlugin{ new net.tfminecraft.simplefactions.mercenary.contract.AttendanceService.Hook(); private ProvinceManager provinceSnapshot = new ProvinceManager(); private ProvinceGrid provinceGrid; - private BukkitTask trackInfrastructureRefreshTask; + private static final long TRACK_REFRESH_TICKS = 300L * 20L; + private BukkitTask trackRefreshTask; private final PlayerVehicleRegistry vehicleRegistry = new PlayerVehicleRegistry(); private VehicleRegistryPersistence vehicleRegistryPersistence; private final InstallationVehicleOwnerSync installationVehicleOwnerSync = @@ -364,16 +365,15 @@ public void onEnable() { if (Cache.supplyHubAutoAccept) { getLogger().info("Hub auto-accept is on."); } - long refreshTicks = Cache.infrastructureTrackRefreshSeconds * 20L; - trackInfrastructureRefreshTask = getServer().getScheduler().runTaskTimer( - this, () -> { refreshTrackProvinces(); }, refreshTicks, refreshTicks); + trackRefreshTask = getServer().getScheduler().runTaskTimer( + this, () -> { refreshTrackProvinces(); }, TRACK_REFRESH_TICKS, TRACK_REFRESH_TICKS); } inventoryManager.start(); vehicleMaintenanceDecayTask.start(); } @Override public void onDisable() { - if (trackInfrastructureRefreshTask != null) trackInfrastructureRefreshTask.cancel(); + if (trackRefreshTask != null) trackRefreshTask.cancel(); net.tfminecraft.simplefactions.integration.rpcharacters.chat.RpCharactersChatIntegration.unregister(); MercenaryStatService.clearAll(); net.tfminecraft.simplefactions.mercenary.company.MercenaryEligibility.reset(); diff --git a/src/main/java/net/tfminecraft/simplefactions/enums/GuildModifier.java b/src/main/java/net/tfminecraft/simplefactions/enums/GuildModifier.java index 63ba9796..13e2491a 100644 --- a/src/main/java/net/tfminecraft/simplefactions/enums/GuildModifier.java +++ b/src/main/java/net/tfminecraft/simplefactions/enums/GuildModifier.java @@ -5,8 +5,6 @@ public enum GuildModifier { TRADE_POWER("#92d665Trade Power", true), TRADE_UPKEEP("#d6645aTrade Upkeep", false), PRODUCTION("#f2c94cProduction", true), - INFRASTRUCTURE("#86d1b0Infrastructure", true), - INFRASTRUCTURE_UPKEEP("#86d1b0Infrastructure Upkeep", false), TRADE_CARRY("#86d1b0Trade Carry", true), HUB_LIMIT("#c99b70Supply Hub Limit", true), HUB_UPKEEP("#d6645aSupply Hub Upkeep", false), diff --git a/src/main/java/net/tfminecraft/simplefactions/guild/hub/InfrastructureMenuCopy.java b/src/main/java/net/tfminecraft/simplefactions/guild/hub/InfrastructureMenuCopy.java deleted file mode 100644 index a81d32bd..00000000 --- a/src/main/java/net/tfminecraft/simplefactions/guild/hub/InfrastructureMenuCopy.java +++ /dev/null @@ -1,55 +0,0 @@ -package net.tfminecraft.simplefactions.guild.hub; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -/** Lore for the realm headline and the installation confirmation. */ -public final class InfrastructureMenuCopy { - private InfrastructureMenuCopy() {} - - public static String headline(double worth) { - return "§7Infrastructure is worth about " + signed(worth) + " a day to your realm"; - } - - public static String headlineUnknown() { - return "§7Infrastructure worth is worked out once a day."; - } - - public static String calculating() { - return "§7Working out what this would earn..."; - } - - public static List installationPreview(InfrastructurePreview.InstallationPreview preview) { - if (preview == null) { - return List.of(calculating()); - } - List lines = new ArrayList<>(); - if (preview.infrastructureHere() > 0) { - lines.add("§a" + signed(preview.infrastructureHere()) + " infrastructure here"); - } else { - lines.add("§7This adds no infrastructure here"); - } - lines.add("§7about " + signed(preview.realmPerDay()) + " a day for your realm"); - if (preview.upkeep() > 0) { - lines.add("§7upkeep " + compact(preview.upkeep())); - } - return lines; - } - - static String signed(double value) { - String number = compact(Math.abs(value)); - if (value < 0) { - return "-" + number; - } - return "+" + number; - } - - static String compact(double value) { - double rounded = Math.round(value * 100.0) / 100.0; - if (Math.abs(rounded - Math.rint(rounded)) < 0.001) { - return Long.toString((long) Math.rint(rounded)); - } - return String.format(Locale.ROOT, "%.2f", rounded); - } -} diff --git a/src/main/java/net/tfminecraft/simplefactions/guild/hub/InfrastructurePreview.java b/src/main/java/net/tfminecraft/simplefactions/guild/hub/InfrastructurePreview.java deleted file mode 100644 index e4d85dbe..00000000 --- a/src/main/java/net/tfminecraft/simplefactions/guild/hub/InfrastructurePreview.java +++ /dev/null @@ -1,112 +0,0 @@ -package net.tfminecraft.simplefactions.guild.hub; - -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import net.tfminecraft.simplefactions.Cache; -import net.tfminecraft.simplefactions.guild.Guild; -import net.tfminecraft.simplefactions.guild.income.EconomicPreview; -import net.tfminecraft.simplefactions.installation.InstallationKind; -import net.tfminecraft.simplefactions.loaders.InstallationConfigLoader; -import net.tfminecraft.simplefactions.managers.ProvinceManager; -import net.tfminecraft.simplefactions.map.provinces.Province; -import net.tfminecraft.simplefactions.objects.Faction; - -/** What one new installation would earn the realm. Used by the build confirmation. */ -public final class InfrastructurePreview { - public record InstallationPreview(double infrastructureHere, double realmPerDay, double upkeep) { - public static final InstallationPreview NONE = new InstallationPreview(0, 0, 0); - } - - private InfrastructurePreview() { - } - - /** - * Adds this kind's infrastructure in the province and reads the realm's net change. - * Writes live trade breakdowns, the same way a law preview does. - */ - public static InstallationPreview previewInstallation( - ProvinceManager live, Faction realm, int provinceId, InstallationKind kind) { - if (live == null || realm == null || kind == null || !live.contains(provinceId)) { - return InstallationPreview.NONE; - } - Province province = live.get(provinceId); - if (province.isSea()) { - return InstallationPreview.NONE; - } - double added = sourceAmount(kind); - Map before = EconomicPreview.projectNets(copy(live)); - ProvinceManager after = copy(live); - if (added > 0) { - after.setExtraInfrastructure(Map.of(provinceId, added)); - } - Map next = EconomicPreview.projectNets(after); - return new InstallationPreview(added, realmDelta(realm, before, next), levelOneUpkeep(kind)); - } - - private static double sourceAmount(InstallationKind kind) { - if (kind == null) { - return 0; - } - return switch (kind) { - case TRAIN_STATION -> Cache.infrastructureStation; - case PORT -> Cache.infrastructurePort; - case AIRPORT -> Cache.infrastructureAirport; - default -> 0; - }; - } - - private static double levelOneUpkeep(InstallationKind kind) { - if (kind == null) { - return 0; - } - try { - return InstallationConfigLoader.getDailyUpkeep(kind, 1); - } catch (IllegalStateException ex) { - return switch (kind) { - case TRAIN_STATION -> 5; - case PORT -> 15; - case AIRPORT -> 20; - case FORT -> 30; - }; - } - } - - private static double realmDelta(Faction realm, Map before, Map after) { - double sum = 0; - Set guilds = new HashSet<>(); - guilds.addAll(before.keySet()); - guilds.addAll(after.keySet()); - for (Guild guild : guilds) { - if (guild == null || !sameRealm(realm, guild.getFaction())) { - continue; - } - sum += after.getOrDefault(guild, 0.0) - before.getOrDefault(guild, 0.0); - } - return round(sum); - } - - private static double round(double value) { - if (!Double.isFinite(value)) { - return 0; - } - return Math.round(value * 100.0) / 100.0; - } - - private static boolean sameRealm(Faction left, Faction right) { - if (left == null || right == null) { - return false; - } - if (left.getId() != null && left.getId().equalsIgnoreCase(right.getId())) { - return true; - } - return net.tfminecraft.simplefactions.managers.RelationManager.sameRealm(left, right); - } - - private static ProvinceManager copy(ProvinceManager live) { - ProvinceManager snapshot = live.createSnapshotShell(); - snapshot.copyAllDataFrom(live); - return snapshot; - } -} diff --git a/src/main/java/net/tfminecraft/simplefactions/guild/hub/VehicleFrameworkTrackProvinces.java b/src/main/java/net/tfminecraft/simplefactions/guild/hub/VehicleFrameworkTrackProvinces.java index 22ddda76..03d9c1ca 100644 --- a/src/main/java/net/tfminecraft/simplefactions/guild/hub/VehicleFrameworkTrackProvinces.java +++ b/src/main/java/net/tfminecraft/simplefactions/guild/hub/VehicleFrameworkTrackProvinces.java @@ -6,7 +6,7 @@ import net.tfminecraft.simplefactions.map.ProvinceGrid; import net.tfminecraft.simplefactions.map.provinces.Province; -/** Track infrastructure sampling uses the same VehicleFramework boundary as hub routes. */ +/** Provinces crossed by railway track. Hub routes use the same VehicleFramework boundary. */ public final class VehicleFrameworkTrackProvinces { private VehicleFrameworkTrackProvinces() {} diff --git a/src/main/java/net/tfminecraft/simplefactions/guild/income/BranchIncomePreview.java b/src/main/java/net/tfminecraft/simplefactions/guild/income/BranchIncomePreview.java index c743c3af..275eebcf 100644 --- a/src/main/java/net/tfminecraft/simplefactions/guild/income/BranchIncomePreview.java +++ b/src/main/java/net/tfminecraft/simplefactions/guild/income/BranchIncomePreview.java @@ -1,8 +1,6 @@ package net.tfminecraft.simplefactions.guild.income; -import java.util.ArrayList; import java.util.EnumMap; -import java.util.List; import java.util.Map; import net.tfminecraft.simplefactions.enums.GuildModifier; @@ -11,9 +9,7 @@ import net.tfminecraft.simplefactions.guild.GuildModifierOverride; import net.tfminecraft.simplefactions.guild.branch.Branch; import net.tfminecraft.simplefactions.guild.branch.BranchModifier; -import net.tfminecraft.simplefactions.managers.FactionManager; import net.tfminecraft.simplefactions.managers.ProvinceManager; -import net.tfminecraft.simplefactions.managers.RelationManager; import net.tfminecraft.simplefactions.objects.Faction; /** @@ -63,58 +59,10 @@ public static double estimate( ProvinceManager after = copy(prepared.snapshot); double baseline = income(before, guild, current); double changed = income(after, guild, hypothetical); - double upkeepChange = Math.max(0.0, hypothetical.getOrDefault(GuildModifier.INFRASTRUCTURE_UPKEEP, 0.0)) - - Math.max(0.0, current.getOrDefault(GuildModifier.INFRASTRUCTURE_UPKEEP, 0.0)); - double net = (changed - baseline) * (1.0 - taxFraction) - upkeepChange; + double net = (changed - baseline) * (1.0 - taxFraction); return Math.round(net * 100.0) / 100.0; } - /** - * The realm guild's infrastructure reaches every guild in the realm, so an - * up or down of that branch is their incomes added together. - */ - public static boolean showsRealm(Guild guild, Branch branch) { - return guild != null - && guild.isBase() - && branch != null - && branch.getModifier(GuildModifier.INFRASTRUCTURE) != null; - } - - /** Guilds and factions as they were on the server thread. The preview does not read the live lists. */ - public static List guildsNow() { - List guilds = new ArrayList<>(); - for (Guild guild : FactionManager.getAllGuilds()) { - if (guild != null) { - guilds.add(guild); - } - } - return List.copyOf(guilds); - } - - public static List factionsNow() { - List factions = new ArrayList<>(); - for (Faction faction : FactionManager.getCopy()) { - if (faction != null) { - factions.add(faction); - } - } - return List.copyOf(factions); - } - - public static double estimateRealm( - Prepared prepared, - Guild realmGuild, - Map current, - Map hypothetical, - List guilds, - List factions) { - double before = realmIncome(prepared, realmGuild, current, guilds, factions); - double after = realmIncome(prepared, realmGuild, hypothetical, guilds, factions); - double upkeepChange = Math.max(0.0, hypothetical.getOrDefault(GuildModifier.INFRASTRUCTURE_UPKEEP, 0.0)) - - Math.max(0.0, current.getOrDefault(GuildModifier.INFRASTRUCTURE_UPKEEP, 0.0)); - return Math.round((after - before - upkeepChange) * 100.0) / 100.0; - } - public static Map modifiers(Guild guild) { EnumMap amounts = new EnumMap<>(GuildModifier.class); for (GuildModifier modifier : GuildModifier.values()) { @@ -155,45 +103,6 @@ private static ProvinceManager copy(ProvinceManager source) { return snapshot; } - private static double realmIncome( - Prepared prepared, - Guild realmGuild, - Map amounts, - List guilds, - List factions) { - ProvinceManager snapshot = copy(prepared.snapshot); - GuildModifierOverride.use(realmGuild, amounts); - try { - snapshot.recalculateQuiet(guilds, factions); - double sum = 0; - Faction realm = realmGuild.getFaction(); - List present = guilds == null ? List.of() : guilds; - for (Guild guild : present) { - if (guild == null || !sameRealm(realm, guild.getFaction())) { - continue; - } - sum += snapshot.getIncome(guild, false) * (1.0 - taxFraction(guild)); - } - return sum; - } finally { - snapshot.clearPreviewLists(); - GuildModifierOverride.clear(); - } - } - - private static boolean sameRealm(Faction realm, Faction guildFaction) { - if (realm == null || guildFaction == null) { - return false; - } - if (realm == guildFaction) { - return true; - } - if (realm.getId() != null && realm.getId().equalsIgnoreCase(guildFaction.getId())) { - return true; - } - return RelationManager.sameRealm(realm, guildFaction); - } - private static double income(ProvinceManager snapshot, Guild guild, Map amounts) { GuildModifierOverride.use(guild, amounts); try { diff --git a/src/main/java/net/tfminecraft/simplefactions/guild/income/Cashflow.java b/src/main/java/net/tfminecraft/simplefactions/guild/income/Cashflow.java index f5fb7834..465ebc2f 100644 --- a/src/main/java/net/tfminecraft/simplefactions/guild/income/Cashflow.java +++ b/src/main/java/net/tfminecraft/simplefactions/guild/income/Cashflow.java @@ -52,8 +52,7 @@ public enum Cashflow { VEHICLE_UPKEEP("#a6659fVehicle Upkeep", true, false), MILITARY_UPKEEP("#a6659fMilitary Upkeep", true, false), NODES("#8a7a5cNodes", true, false), - SUPPLY_HUBS("#b5835aSupply hubs", true, false), - INFRASTRUCTURE_UPKEEP("#86d1b0Infrastructure", true, false); + SUPPLY_HUBS("#b5835aSupply hubs", true, false); private final String display; private final boolean affectsInflation; diff --git a/src/main/java/net/tfminecraft/simplefactions/guild/income/Ledger.java b/src/main/java/net/tfminecraft/simplefactions/guild/income/Ledger.java index 15602a90..06984318 100644 --- a/src/main/java/net/tfminecraft/simplefactions/guild/income/Ledger.java +++ b/src/main/java/net/tfminecraft/simplefactions/guild/income/Ledger.java @@ -14,7 +14,6 @@ import net.tfminecraft.simplefactions.SimpleFactions; import net.tfminecraft.simplefactions.guild.Guild; -import net.tfminecraft.simplefactions.guild.GuildModifierOverride; import net.tfminecraft.simplefactions.guild.hub.SupplyHub; import net.tfminecraft.simplefactions.guild.hub.HubTaxBreakdown; import net.tfminecraft.simplefactions.guild.hub.SupplyHubCommands; @@ -34,7 +33,6 @@ import net.tfminecraft.simplefactions.utils.Formatter; import net.tfminecraft.simplefactions.utils.PostSettlementPayouts.PlayerUuidLookup; import net.tfminecraft.simplefactions.enums.FactionModifiers; -import net.tfminecraft.simplefactions.enums.GuildModifier; import net.tfminecraft.simplefactions.enums.Rules; import net.tfminecraft.simplefactions.government.proposal.TaxTarget; import net.tfminecraft.simplefactions.mercenary.company.MercenaryCompany; @@ -377,9 +375,6 @@ public double getIncome(Cashflow cashflow) { case SUPPLY_HUBS: amount = -SupplyHubService.dailyCost(guild); break; - case INFRASTRUCTURE_UPKEEP: - amount = -Math.max(0, GuildModifierOverride.resolve(guild, GuildModifier.INFRASTRUCTURE_UPKEEP)); - break; //Mercenary contracts case MERCENARY_CONTRACT: amount = getAggregatedContractEarnings(); @@ -624,7 +619,6 @@ public double getNetIncome() { case MILITARY_UPKEEP: case NODES: case SUPPLY_HUBS: - case INFRASTRUCTURE_UPKEEP: case PENALTIES: case GUILD_PAYMENTS: case OVERLORD_TAX: @@ -703,7 +697,6 @@ public double getDividendBase() { case MILITARY_UPKEEP: case NODES: case SUPPLY_HUBS: - case INFRASTRUCTURE_UPKEEP: case PENALTIES: case GUILD_PAYMENTS: case OVERLORD_TAX: @@ -1129,7 +1122,6 @@ private void applySettlementFor(Cashflow cf, DailyGuildTransfers buffer) { case NODES: // Supply hubs are a sink. Unpaid hubs were already removed, newest first. case SUPPLY_HUBS: - case INFRASTRUCTURE_UPKEEP: buffer.addExternalDelta(guild, getIncome(cf)); return; diff --git a/src/main/java/net/tfminecraft/simplefactions/loaders/ConfigLoader.java b/src/main/java/net/tfminecraft/simplefactions/loaders/ConfigLoader.java index e7308386..e3bf4efb 100644 --- a/src/main/java/net/tfminecraft/simplefactions/loaders/ConfigLoader.java +++ b/src/main/java/net/tfminecraft/simplefactions/loaders/ConfigLoader.java @@ -73,20 +73,6 @@ public void loadConfig(File configFile) { Cache.mercenaryDefaultBreachRefund = config.getDouble("mercenary-default-breach-refund", 500.0); net.tfminecraft.simplefactions.guild.hub.SupplyHubService.loadConfig(config); net.tfminecraft.simplefactions.guild.hub.HubTransport.loadConfig(config); - double infrastructureFull = config.getDouble("infrastructure.full", 20); - Cache.infrastructureFull = Double.isFinite(infrastructureFull) && infrastructureFull > 0 - ? infrastructureFull : 20; - Cache.infrastructureTarget = config.getDouble("infrastructure.target", 0.75); - Cache.infrastructureWildernessSpread = config.getDouble("infrastructure.wilderness-spread", 0.25); - double infrastructureSpreadFloor = config.getDouble("infrastructure.spread-floor", 0.5); - Cache.infrastructureSpreadFloor = Double.isFinite(infrastructureSpreadFloor) && infrastructureSpreadFloor > 0 - ? infrastructureSpreadFloor : 0.5; - Cache.infrastructureStation = config.getDouble("infrastructure.station", 10); - Cache.infrastructurePort = config.getDouble("infrastructure.port", 10); - Cache.infrastructureAirport = config.getDouble("infrastructure.airport", 5); - Cache.infrastructureTrack = config.getDouble("infrastructure.track", 10); - Cache.infrastructureTrackRefreshSeconds = Math.max(30, - config.getInt("infrastructure.track-refresh-seconds", 300)); Cache.settlementLargePopulationThreshold = config.getInt("settlement-large-population-threshold", 8); Cache.portSeaProximityBlocks = config.getInt("port-sea-proximity-blocks", 20); diff --git a/src/main/java/net/tfminecraft/simplefactions/managers/CommandManager.java b/src/main/java/net/tfminecraft/simplefactions/managers/CommandManager.java index f10c3697..f1816611 100644 --- a/src/main/java/net/tfminecraft/simplefactions/managers/CommandManager.java +++ b/src/main/java/net/tfminecraft/simplefactions/managers/CommandManager.java @@ -40,7 +40,6 @@ import net.tfminecraft.simplefactions.installation.Installation; import net.tfminecraft.simplefactions.installation.InstallationKind; import net.tfminecraft.simplefactions.installation.handler.ConstructResult; -import net.tfminecraft.simplefactions.managers.inventory.InstallationBuildConfirm; import net.tfminecraft.simplefactions.settlement.handler.CapitalResult; import net.tfminecraft.simplefactions.tiers.Title; import net.tfminecraft.simplefactions.tiers.admin.TitleAdminCommand; @@ -628,15 +627,15 @@ private boolean dispatchCommand(CommandSender sender, Command cmd, String label, return true; } String name = String.join(" ", Arrays.copyOfRange(args, 2, args.length)); - if (InstallationBuildConfirm.open( - p, - f, + ConstructResult result = f.getInstallationHandler().construct( kind, name, province, p.getLocation().getBlockX(), - p.getLocation().getBlockZ())) { - p.playSound(p, Sound.BLOCK_NOTE_BLOCK_BIT, 1f, 1f); + p.getLocation().getBlockZ()); + p.sendMessage(result.getMessage()); + if(result.isSuccess()) { + p.playSound(p, Sound.BLOCK_ANVIL_USE, 1f, 1f); } return true; } else if(cmd.getName().equalsIgnoreCase(cmd1) && args[0].equalsIgnoreCase("deconstruct")) { diff --git a/src/main/java/net/tfminecraft/simplefactions/managers/InventoryManager.java b/src/main/java/net/tfminecraft/simplefactions/managers/InventoryManager.java index 94a584a7..8a11abb0 100644 --- a/src/main/java/net/tfminecraft/simplefactions/managers/InventoryManager.java +++ b/src/main/java/net/tfminecraft/simplefactions/managers/InventoryManager.java @@ -37,7 +37,6 @@ import net.tfminecraft.simplefactions.managers.holder.SFInventoryHolder; import net.tfminecraft.simplefactions.managers.holder.WarInventoryHolder; import net.tfminecraft.simplefactions.managers.inventory.CampaignInstallationPickView; -import net.tfminecraft.simplefactions.managers.inventory.InstallationBuildConfirm; import net.tfminecraft.simplefactions.managers.inventory.CampaignRaidLaunchView; import net.tfminecraft.simplefactions.managers.inventory.CampaignView; import net.tfminecraft.simplefactions.managers.inventory.CompanyView; @@ -1002,8 +1001,6 @@ public void clearPendingOnQuit(PlayerQuitEvent e) { if (pendingCompanyFounds.remove(e.getPlayer()) != null) { confirming.remove(e.getPlayer()); } - InstallationBuildConfirm.forget(e.getPlayer()); - confirming.remove(e.getPlayer()); slotChanges.remove(e.getPlayer()); } @@ -1488,17 +1485,6 @@ public void clickButton(InventoryClickEvent e) { } return; } - key = new NamespacedKey(SimpleFactions.plugin, "installation_build"); - data = m.getPersistentDataContainer().get(key, PersistentDataType.STRING); - if (data != null) { - if (item.getType().equals(Material.RED_CONCRETE)) { - InstallationBuildConfirm.cancel(p); - } else { - InstallationBuildConfirm.accept(p); - } - confirming.remove(p); - return; - } key = new NamespacedKey(SimpleFactions.plugin, "installation"); data = m.getPersistentDataContainer().get(key, PersistentDataType.STRING); if(data != null) { diff --git a/src/main/java/net/tfminecraft/simplefactions/managers/ProvinceManager.java b/src/main/java/net/tfminecraft/simplefactions/managers/ProvinceManager.java index e274c0b4..09387e0f 100644 --- a/src/main/java/net/tfminecraft/simplefactions/managers/ProvinceManager.java +++ b/src/main/java/net/tfminecraft/simplefactions/managers/ProvinceManager.java @@ -25,8 +25,6 @@ import net.tfminecraft.simplefactions.guild.network.TradeGraph; import net.tfminecraft.simplefactions.map.provinces.Province; import net.tfminecraft.simplefactions.map.provinces.ProvinceDataEntry; -import net.tfminecraft.simplefactions.map.infra.InfrastructureSources; -import net.tfminecraft.simplefactions.map.infra.InfrastructureSpread; import net.tfminecraft.simplefactions.objects.Bracket; import net.tfminecraft.simplefactions.objects.Faction; import net.tfminecraft.simplefactions.Cache; @@ -48,8 +46,6 @@ public class ProvinceManager { /** Set on a copy so a preview keeps the graph and hubs it was given, off the server thread. */ private HighwaySnapshot highwayCapture; private Map> installationAccess = new HashMap<>(); - private boolean infrastructureSuppressed; - private Map extraInfrastructure; private long stateVersion = 0; private long lastCalculatedVersion = -1; @@ -106,19 +102,6 @@ public void setHighwayOverride(TradeGraph graph, Map> hubbe hubbedByGuild == null ? Map.of() : hubbedByGuild); } - /** Snapshot-only. The next recalculation writes 0 infrastructure on every province. */ - public void setInfrastructureSuppressed(boolean suppressed) { - infrastructureSuppressed = suppressed; - } - - /** - * Snapshot-only source added before the spread. Sea and water provinces are ignored. - * A null or empty map adds nothing. Copies do not inherit this. - */ - public void setExtraInfrastructure(Map extra) { - extraInfrastructure = extra == null || extra.isEmpty() ? null : Map.copyOf(extra); - } - private HighwaySnapshot highway() { return highwayCapture != null ? highwayCapture : HighwaySnapshot.current(); } @@ -151,7 +134,6 @@ public void recalculate() { try { installationAccess = new HashMap<>(); HubNetwork.refreshIfLive(this); - recalculateInfrastructure(); dropMissingGuilds(); for(Guild g : FactionManager.getAllGuilds()) { if (!g.hasCapital()) continue; @@ -182,7 +164,6 @@ public void recalculateQuiet(List guilds, List factions) { try { installationAccess = new HashMap<>(); HubNetwork.refreshIfLive(this); - recalculateInfrastructure(); dropExcept(previewGuilds); for (Guild guild : previewGuilds) { if (guild != null && guild.hasCapital()) { @@ -213,7 +194,6 @@ public void recalculateForSingleGuild(Guild g, boolean save) { InstallationAccess.beginRecalculation(); try { installationAccess = new HashMap<>(); - recalculateInfrastructure(); if (!g.hasCapital()) return; HubNetwork.refreshIfLive(this); dropMissingGuilds(); @@ -230,43 +210,6 @@ public void recalculateForSingleGuild(Guild g, boolean save) { } } - private void recalculateInfrastructure() { - if (infrastructureSuppressed) { - for (Province province : provinces.values()) { - province.setInfrastructure(0); - } - return; - } - Map graph = new HashMap<>(); - for (Province province : provinces.values()) { - Faction realm = InstallationAccess.topRealm( - previewFactions != null ? ownerOf(province.getId()) : province.getOwner()); - String origin = realm == null ? null : realm.getId().toLowerCase(Locale.ROOT); - graph.put(province.getId(), new InfrastructureSpread.Node( - province.getTradeCarry(), !province.isSea(), origin, province.getNeighbours())); - } - Map sources = InfrastructureSources.collect( - provinces, - previewGuilds != null ? previewGuilds : FactionManager.getAllGuilds(), - previewFactions != null ? previewFactions : FactionManager.getCopy(), - net.tfminecraft.simplefactions.map.infra.TrackProvinceCache.live().provinces()); - if (extraInfrastructure != null) { - for (Map.Entry extra : extraInfrastructure.entrySet()) { - Province province = provinces.get(extra.getKey()); - if (province == null || province.isSea() || extra.getValue() == null || extra.getValue() <= 0) { - continue; - } - sources.merge(extra.getKey(), extra.getValue(), Double::sum); - } - } - Map infrastructure = InfrastructureSpread.spread( - graph, sources, Cache.infrastructureWildernessSpread, Cache.infrastructureSpreadFloor); - for (Province province : provinces.values()) { - InfrastructureSpread.Arrival arrival = infrastructure.get(province.getId()); - province.setInfrastructure(arrival == null ? 0 : arrival.amount()); - } - } - private void recalculateProsperity() { for (Province p : provinces.values()) { p.calculateProsperity(); @@ -489,7 +432,6 @@ public void copyAllDataFrom(ProvinceManager source) { } dst.setProsperity(src.getProsperity()); - dst.setInfrastructure(src.getInfrastructure()); } } diff --git a/src/main/java/net/tfminecraft/simplefactions/managers/inventory/BranchIncomePreviewService.java b/src/main/java/net/tfminecraft/simplefactions/managers/inventory/BranchIncomePreviewService.java index de29d974..90881048 100644 --- a/src/main/java/net/tfminecraft/simplefactions/managers/inventory/BranchIncomePreviewService.java +++ b/src/main/java/net/tfminecraft/simplefactions/managers/inventory/BranchIncomePreviewService.java @@ -1,6 +1,5 @@ package net.tfminecraft.simplefactions.managers.inventory; -import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicLong; import java.util.logging.Level; @@ -16,7 +15,6 @@ import net.tfminecraft.simplefactions.enums.GuildModifier; import net.tfminecraft.simplefactions.guild.Guild; import net.tfminecraft.simplefactions.guild.branch.Branch; -import net.tfminecraft.simplefactions.objects.Faction; import net.tfminecraft.simplefactions.guild.income.BranchIncomePreview; import net.tfminecraft.simplefactions.keys.Keys; @@ -52,9 +50,6 @@ public static void schedule( Map current = BranchIncomePreview.modifiers(guild); Map hypothetical = BranchIncomePreview.adjust(current, branch, level, levelDelta); double taxFraction = BranchIncomePreview.taxFraction(guild); - boolean realmWide = BranchIncomePreview.showsRealm(guild, branch); - List realmGuilds = realmWide ? BranchIncomePreview.guildsNow() : List.of(); - List realmFactions = realmWide ? BranchIncomePreview.factionsNow() : List.of(); String guildId = guild.getId(); String branchId = branch.getId(); long token = TOKENS.incrementAndGet(); @@ -64,10 +59,7 @@ public static void schedule( Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { double delta; try { - delta = realmWide - ? BranchIncomePreview.estimateRealm( - prepared, guild, current, hypothetical, realmGuilds, realmFactions) - : BranchIncomePreview.estimate(prepared, guild, current, hypothetical, taxFraction); + delta = BranchIncomePreview.estimate(prepared, guild, current, hypothetical, taxFraction); } catch (RuntimeException ex) { plugin.getLogger().log( Level.WARNING, diff --git a/src/main/java/net/tfminecraft/simplefactions/managers/inventory/GuildCreator.java b/src/main/java/net/tfminecraft/simplefactions/managers/inventory/GuildCreator.java index 7f1a30ad..a8484787 100644 --- a/src/main/java/net/tfminecraft/simplefactions/managers/inventory/GuildCreator.java +++ b/src/main/java/net/tfminecraft/simplefactions/managers/inventory/GuildCreator.java @@ -27,7 +27,6 @@ import net.tfminecraft.simplefactions.SimpleFactions; import net.tfminecraft.simplefactions.guild.branch.Branch; import net.tfminecraft.simplefactions.guild.branch.BranchModifier; -import net.tfminecraft.simplefactions.guild.income.BranchIncomePreview; import net.tfminecraft.simplefactions.guild.income.Cashflow; import net.tfminecraft.simplefactions.guild.income.Ledger; import net.tfminecraft.simplefactions.guild.income.LedgerHistory; @@ -356,7 +355,7 @@ private List upgradeLore(Guild guild, Branch branch, Double delta) { lore.add(""); lore.add(StringFormatter.formatHex("#d4c9aeCurrent Net Trade Income: #7fbd73"+net.tfminecraft.simplefactions.utils.Formatter.formatDouble( guild.getTradeBreakdown().getNetTradeIncome() - guild.getHubTaxBreakdown().getTotalTax()))); - lore.add(incomeChangeLine(delta, BranchIncomePreview.showsRealm(guild, branch))); + lore.add(incomeChangeLine(delta)); } lore.add(""); lore.add(StringFormatter.formatHex("#50e846§lClick to Upgrade")); @@ -403,7 +402,7 @@ private List downgradeLore(Guild guild, Branch branch, Double delta) { } else { lore.add(StringFormatter.formatHex("#d4c9aeCurrent Net Trade Income: #7fbd73"+net.tfminecraft.simplefactions.utils.Formatter.formatDouble( guild.getTradeBreakdown().getNetTradeIncome() - guild.getHubTaxBreakdown().getTotalTax()))); - lore.add(incomeChangeLine(delta, BranchIncomePreview.showsRealm(guild, branch))); + lore.add(incomeChangeLine(delta)); } lore.add(""); lore.add(StringFormatter.formatHex( @@ -414,16 +413,15 @@ private List downgradeLore(Guild guild, Branch branch, Double delta) { return lore; } - String incomeChangeLine(Double delta, boolean realm) { - String label = realm ? "Estimated Realm Income Change" : "Estimated Income Change"; + private String incomeChangeLine(Double delta) { if (delta == null) { - return StringFormatter.formatHex("#f2e5c2" + label + "#d6cf69: #7a706aCalculating..."); + return StringFormatter.formatHex("#f2e5c2Estimated Income Change#d6cf69: #7a706aCalculating..."); } if (delta.isNaN()) { return StringFormatter.formatHex("#cf493aIncome estimate unavailable"); } return StringFormatter.formatHex( - "#f2e5c2" + label + "#d6cf69: " + "#f2e5c2Estimated Income Change#d6cf69: " + (delta >= 0 ? "#4fd945+" : "#cf493a") + String.format("%.2f", delta) + "d/day" diff --git a/src/main/java/net/tfminecraft/simplefactions/managers/inventory/InstallationBuildConfirm.java b/src/main/java/net/tfminecraft/simplefactions/managers/inventory/InstallationBuildConfirm.java deleted file mode 100644 index d371aa7d..00000000 --- a/src/main/java/net/tfminecraft/simplefactions/managers/inventory/InstallationBuildConfirm.java +++ /dev/null @@ -1,190 +0,0 @@ -package net.tfminecraft.simplefactions.managers.inventory; - -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicLong; -import java.util.logging.Level; - -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.NamespacedKey; -import org.bukkit.Sound; -import org.bukkit.entity.Player; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.persistence.PersistentDataType; - -import net.tfminecraft.simplefactions.SimpleFactions; -import net.tfminecraft.simplefactions.guild.hub.InfrastructureMenuCopy; -import net.tfminecraft.simplefactions.guild.hub.InfrastructurePreview; -import net.tfminecraft.simplefactions.installation.InstallationKind; -import net.tfminecraft.simplefactions.installation.handler.ConstructResult; -import net.tfminecraft.simplefactions.managers.FactionManager; -import net.tfminecraft.simplefactions.managers.InventoryManager; -import net.tfminecraft.simplefactions.managers.ProvinceManager; -import net.tfminecraft.simplefactions.objects.Faction; - -/** Confirmation chest for /faction construct, with the installation preview painted in. */ -public final class InstallationBuildConfirm { - private static final AtomicLong TOKENS = new AtomicLong(); - private static final Map PENDING = new ConcurrentHashMap<>(); - - private InstallationBuildConfirm() {} - - private record Pending( - Faction faction, - InstallationKind kind, - String name, - int province, - int blockX, - int blockZ, - long token) {} - - public static boolean open( - Player player, - Faction faction, - InstallationKind kind, - String name, - int province, - int blockX, - int blockZ) { - SimpleFactions plugin = SimpleFactions.plugin; - InventoryManager menus = FactionManager.getInv(); - if (player == null || faction == null || kind == null || plugin == null || !plugin.isEnabled() || menus == null) { - if (player != null) { - player.sendMessage("§cCould not open the construction confirmation."); - } - return false; - } - long token = TOKENS.incrementAndGet(); - PENDING.put(player.getUniqueId(), new Pending(faction, kind, name, province, blockX, blockZ, token)); - menus.confirming.put(player, faction); - - Inventory inventory = plugin.getServer().createInventory(null, 27, "§7Confirm Action"); - inventory.setItem(13, paper(plugin, name, token, List.of(InfrastructureMenuCopy.calculating()))); - inventory.setItem(11, menus.createButton("confirm", "installation_build", "build")); - inventory.setItem(15, menus.createButton("cancel", "installation_build", "build")); - player.openInventory(inventory); - - ProvinceManager live = plugin.getProvinceManager(); - ProvinceManager snapshot = null; - if (live != null) { - snapshot = live.createSnapshotShell(); - snapshot.copyAllDataFrom(live); - } - ProvinceManager provinces = snapshot; - Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { - List lore; - try { - InfrastructurePreview.InstallationPreview preview = InfrastructurePreview.previewInstallation( - provinces, faction, province, kind); - lore = InfrastructureMenuCopy.installationPreview(preview); - } catch (RuntimeException ex) { - plugin.getLogger().log( - Level.WARNING, - "Installation preview failed for " + kind + " in province " + province, - ex); - lore = List.of("§cIncome estimate unavailable"); - } - if (!plugin.isEnabled()) { - return; - } - List lines = lore; - Bukkit.getScheduler().runTask(plugin, () -> publish(player, token, lines)); - }); - return true; - } - - public static void accept(Player player) { - if (player == null) { - return; - } - Pending pending = PENDING.remove(player.getUniqueId()); - if (pending == null || pending.faction == null) { - player.sendMessage("§cThat construction is no longer waiting."); - player.closeInventory(); - return; - } - if (pending.faction.getLeader() == null - || !pending.faction.getLeader().equalsIgnoreCase(player.getName())) { - player.sendMessage("§cYou need to be a faction leader to construct installations"); - player.closeInventory(); - return; - } - if (pending.faction.getInstallationHandler() == null) { - player.sendMessage("§cCould not construct that installation."); - player.closeInventory(); - return; - } - ConstructResult result = pending.faction.getInstallationHandler().construct( - pending.kind, pending.name, pending.province, pending.blockX, pending.blockZ); - player.sendMessage(result.getMessage()); - player.playSound( - player, - result.isSuccess() ? Sound.BLOCK_ANVIL_USE : Sound.BLOCK_NOTE_BLOCK_BIT, - 1f, - 1f); - player.closeInventory(); - } - - public static void cancel(Player player) { - if (player == null) { - return; - } - PENDING.remove(player.getUniqueId()); - player.closeInventory(); - player.playSound(player, Sound.BLOCK_NOTE_BLOCK_BIT, 1f, 1f); - } - - public static void forget(Player player) { - if (player != null) { - PENDING.remove(player.getUniqueId()); - } - } - - @SuppressWarnings("deprecation") - private static void publish(Player player, long token, List lore) { - if (!player.isOnline() || player.getOpenInventory() == null) { - return; - } - if (!"§7Confirm Action".equals(player.getOpenInventory().getTitle())) { - return; - } - Inventory inventory = player.getOpenInventory().getTopInventory(); - ItemStack item = inventory.getItem(13); - if (!matches(item, token)) { - return; - } - ItemMeta meta = item.getItemMeta(); - meta.setLore(lore); - item.setItemMeta(meta); - inventory.setItem(13, item); - } - - @SuppressWarnings("deprecation") - private static ItemStack paper(SimpleFactions plugin, String name, long token, List lore) { - ItemStack item = new ItemStack(Material.PAPER); - ItemMeta meta = item.getItemMeta(); - meta.setDisplayName(name == null || name.isBlank() ? "§6Installation" : "§6" + name); - meta.setLore(lore); - meta.getPersistentDataContainer().set(tokenKey(plugin), PersistentDataType.LONG, token); - item.setItemMeta(meta); - return item; - } - - private static boolean matches(ItemStack item, long token) { - SimpleFactions plugin = SimpleFactions.plugin; - if (plugin == null || item == null || !item.hasItemMeta()) { - return false; - } - Long stamped = item.getItemMeta().getPersistentDataContainer().get(tokenKey(plugin), PersistentDataType.LONG); - return stamped != null && stamped == token; - } - - private static NamespacedKey tokenKey(SimpleFactions plugin) { - return new NamespacedKey(plugin, "installation_preview"); - } -} diff --git a/src/main/java/net/tfminecraft/simplefactions/map/Compiler.java b/src/main/java/net/tfminecraft/simplefactions/map/Compiler.java index 3d71ae7e..9414a776 100644 --- a/src/main/java/net/tfminecraft/simplefactions/map/Compiler.java +++ b/src/main/java/net/tfminecraft/simplefactions/map/Compiler.java @@ -7,7 +7,6 @@ import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.List; -import java.util.Locale; import java.util.Map; import com.google.gson.Gson; @@ -16,7 +15,6 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; -import net.tfminecraft.simplefactions.Cache; import net.tfminecraft.simplefactions.SimpleFactions; import net.tfminecraft.simplefactions.guild.Guild; import net.tfminecraft.simplefactions.managers.FactionManager; @@ -24,7 +22,6 @@ import net.tfminecraft.simplefactions.managers.TitleManager; import net.tfminecraft.simplefactions.managers.WarManager; import net.tfminecraft.simplefactions.map.export.OccupationMapExport; -import net.tfminecraft.simplefactions.map.infra.EffectiveTerrain; import net.tfminecraft.simplefactions.map.provinces.Province; import net.tfminecraft.simplefactions.map.provinces.ProvinceDataEntry; @@ -96,20 +93,6 @@ static JsonObject provinceToJson(Province p, String occupierId) { } o.add("trade", trade); - if (!p.isSea()) { - double terrain = p.getTradeCarry(); - double infrastructure = p.getInfrastructure(); - o.addProperty("terrain", p.getTerrain().name().toLowerCase(Locale.ROOT)); - o.addProperty("terrain_value", terrain); - if (infrastructure > 0 && Double.isFinite(Cache.infrastructureFull) && Cache.infrastructureFull > 0) { - o.addProperty("infrastructure", r2(infrastructure)); - o.addProperty("infrastructure_fill", r2(Math.max(0, Math.min(1, - infrastructure / Cache.infrastructureFull)))); - } - o.addProperty("effective_terrain", r2(EffectiveTerrain.calculate(terrain, infrastructure, - Cache.infrastructureFull, Cache.infrastructureTarget, 1))); - } - return o; } diff --git a/src/main/java/net/tfminecraft/simplefactions/map/infra/EffectiveTerrain.java b/src/main/java/net/tfminecraft/simplefactions/map/infra/EffectiveTerrain.java deleted file mode 100644 index 6f1f9b03..00000000 --- a/src/main/java/net/tfminecraft/simplefactions/map/infra/EffectiveTerrain.java +++ /dev/null @@ -1,11 +0,0 @@ -package net.tfminecraft.simplefactions.map.infra; - -public final class EffectiveTerrain { - private EffectiveTerrain() {} - - public static double calculate(double terrain, double infrastructure, double full, double target, double access) { - if (terrain >= target || infrastructure <= 0 || full <= 0) return terrain; - double fill = Math.min(1, infrastructure / full); - return terrain + (target - terrain) * fill * access; - } -} diff --git a/src/main/java/net/tfminecraft/simplefactions/map/infra/InfrastructureSources.java b/src/main/java/net/tfminecraft/simplefactions/map/infra/InfrastructureSources.java deleted file mode 100644 index d646a38e..00000000 --- a/src/main/java/net/tfminecraft/simplefactions/map/infra/InfrastructureSources.java +++ /dev/null @@ -1,50 +0,0 @@ -package net.tfminecraft.simplefactions.map.infra; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import net.tfminecraft.simplefactions.Cache; -import net.tfminecraft.simplefactions.enums.GuildModifier; -import net.tfminecraft.simplefactions.guild.Guild; -import net.tfminecraft.simplefactions.guild.GuildModifierOverride; -import net.tfminecraft.simplefactions.installation.Installation; -import net.tfminecraft.simplefactions.map.provinces.Province; -import net.tfminecraft.simplefactions.objects.Faction; - -public final class InfrastructureSources { - private InfrastructureSources() {} - - public static Map collect( - Map provinces, Collection guilds, Collection factions, - Set trackProvinces) { - Map sources = new HashMap<>(); - for (Guild guild : guilds) { - if (guild == null || !guild.isBase() || !guild.hasCapital()) continue; - add(provinces, sources, guild.getCapital(), GuildModifierOverride.resolve(guild, GuildModifier.INFRASTRUCTURE)); - } - for (Faction faction : factions) { - if (faction == null || faction.getInstallationHandler() == null) continue; - for (Installation installation : faction.getInstallationHandler().getAll()) { - double amount = switch (installation.getKind()) { - case TRAIN_STATION -> Cache.infrastructureStation; - case PORT -> Cache.infrastructurePort; - case AIRPORT -> Cache.infrastructureAirport; - default -> 0; - }; - add(provinces, sources, installation.getProvince(), amount); - } - } - for (Integer id : trackProvinces) { - add(provinces, sources, id, Cache.infrastructureTrack); - } - return sources; - } - - private static void add(Map provinces, Map sources, int id, double amount) { - Province province = provinces.get(id); - if (province == null || province.isSea() || amount <= 0) return; - sources.merge(id, amount, Double::sum); - } -} diff --git a/src/main/java/net/tfminecraft/simplefactions/map/infra/InfrastructureSpread.java b/src/main/java/net/tfminecraft/simplefactions/map/infra/InfrastructureSpread.java deleted file mode 100644 index 5c41a59d..00000000 --- a/src/main/java/net/tfminecraft/simplefactions/map/infra/InfrastructureSpread.java +++ /dev/null @@ -1,49 +0,0 @@ -package net.tfminecraft.simplefactions.map.infra; - -import java.util.Collection; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.PriorityQueue; - -public final class InfrastructureSpread { - private InfrastructureSpread() {} - - public record Node(double terrain, boolean land, String realm, Collection neighbours) {} - public record Arrival(double amount, String origin) {} - private record Step(int province, Arrival arrival) {} - - public static Map spread( - Map provinces, Map sources, double wilderness, double floor) { - Map best = new HashMap<>(); - PriorityQueue pending = new PriorityQueue<>( - Comparator.comparingDouble((Step step) -> step.arrival().amount()).reversed() - .thenComparingInt(Step::province)); - for (Map.Entry source : sources.entrySet()) { - Node province = provinces.get(source.getKey()); - if (province == null || !province.land() || source.getValue() <= 0) continue; - Arrival arrival = new Arrival(source.getValue(), province.realm()); - best.put(source.getKey(), arrival); - pending.add(new Step(source.getKey(), arrival)); - } - while (!pending.isEmpty()) { - Step step = pending.remove(); - Arrival here = step.arrival(); - if (!here.equals(best.get(step.province())) || here.amount() < floor) continue; - for (Integer neighbour : provinces.get(step.province()).neighbours()) { - Node entered = provinces.get(neighbour); - if (entered == null || !entered.land()) continue; - if (entered.realm() != null && !Objects.equals(entered.realm(), here.origin())) continue; - double amount = here.amount() * entered.terrain(); - if (entered.realm() == null) amount *= wilderness; - Arrival previous = best.get(neighbour); - if (amount < floor || (previous != null && amount <= previous.amount())) continue; - Arrival arrival = new Arrival(amount, here.origin()); - best.put(neighbour, arrival); - pending.add(new Step(neighbour, arrival)); - } - } - return best; - } -} diff --git a/src/main/java/net/tfminecraft/simplefactions/map/infra/TrackProvinceCache.java b/src/main/java/net/tfminecraft/simplefactions/map/infra/TrackProvinceCache.java index 652018e6..8c4db506 100644 --- a/src/main/java/net/tfminecraft/simplefactions/map/infra/TrackProvinceCache.java +++ b/src/main/java/net/tfminecraft/simplefactions/map/infra/TrackProvinceCache.java @@ -23,7 +23,7 @@ public Set provinces() { public void vehicleFrameworkUnavailable(Consumer info) { if (!vehicleFrameworkUnavailableLogged) { vehicleFrameworkUnavailableLogged = true; - info.accept("VehicleFramework is not enabled; railway track gives no infrastructure."); + info.accept("VehicleFramework is not enabled; railway track is not read."); } } @@ -35,7 +35,7 @@ public boolean refresh(Supplier> sampler, Runnable recalculate, Con sampled = Set.of(); if (!warned) { warned = true; - warning.accept("Could not read VehicleFramework tracks; track infrastructure is disabled."); + warning.accept("Could not read VehicleFramework tracks; track provinces are treated as empty."); } } if (provinces.equals(sampled)) return false; diff --git a/src/main/java/net/tfminecraft/simplefactions/map/provinces/Province.java b/src/main/java/net/tfminecraft/simplefactions/map/provinces/Province.java index 3a686be3..4d790145 100644 --- a/src/main/java/net/tfminecraft/simplefactions/map/provinces/Province.java +++ b/src/main/java/net/tfminecraft/simplefactions/map/provinces/Province.java @@ -17,8 +17,6 @@ import net.tfminecraft.simplefactions.managers.TitleManager; import net.tfminecraft.simplefactions.objects.Faction; import net.tfminecraft.simplefactions.objects.FactionModifier; -import net.tfminecraft.simplefactions.map.infra.EffectiveTerrain; -import net.tfminecraft.simplefactions.guild.network.InstallationAccess; import net.tfminecraft.simplefactions.utils.ModifierMerger; import net.tfminecraft.simplefactions.enums.FactionModifiers; import net.tfminecraft.simplefactions.enums.GuildModifier; @@ -34,7 +32,6 @@ public class Province { private int centerX; private int centerZ; private double prosperity = 0; - private double infrastructure = 0; private final Set neighbours = new HashSet<>(); public Province() { @@ -91,7 +88,7 @@ public void calculateTrade( double amount; double carry = GuildModifierOverride.resolve(guild, GuildModifier.TRADE_CARRY); double effectiveDistance = distance / Math.pow(carry, 1.1); - double factor = Math.pow(getTradeCarry(guild), effectiveDistance); + double factor = Math.pow(getTradeCarry(), effectiveDistance); if (prev == -1) { // Capital province amount = net.tfminecraft.simplefactions.government.stability.StabilityDebuffs.realmSeed( @@ -133,7 +130,7 @@ public void calculateProduction( int distance ) { double amount; - double terrainFactor = Math.pow(getTradeCarry(guild), 0.5); + double terrainFactor = Math.pow(getTradeCarry(), 0.5); double factor = terrainFactor*getTradeFactor(guild); if (prev == null) { @@ -170,7 +167,7 @@ public void calculateProduction( public double getTradeFactor(Guild guild) { double trade = getGuildTrade(guild); if(trade == 0) return 0.05; - double K = 2.5 / Math.pow(getTradeCarry(guild), 0.5); + double K = 2.5 / Math.pow(getTradeCarry(), 0.5); return (trade / (trade + K)); } @@ -323,7 +320,7 @@ private void spreadHubProduction( ProvinceDataEntry prev, int distance ) { - double factor = Math.pow(getTradeCarry(guild), 0.5) * getTradeFactor(guild); + double factor = Math.pow(getTradeCarry(), 0.5) * getTradeFactor(guild); double amount = prev.getProduction() * factor; if (amount < 0.1) return; @@ -350,15 +347,6 @@ public double getTradeCarry() { return Cache.tradeCarry.getOrDefault(terrain, 0.5); } - public double getTradeCarry(Guild guild) { - double terrain = getTradeCarry(); - if (guild == null || isSea() || infrastructure <= 0 || terrain >= Cache.infrastructureTarget) return terrain; - return EffectiveTerrain.calculate(terrain, infrastructure, Cache.infrastructureFull, - Cache.infrastructureTarget, InstallationAccess.of(guild.getFaction(), getOwner())); - } - - public double getInfrastructure() { return infrastructure; } - public void setInfrastructure(double amount) { infrastructure = amount; } public Set getNeighbours() { return Collections.unmodifiableSet(neighbours); } diff --git a/src/main/resources/Guilds/branches.yml b/src/main/resources/Guilds/branches.yml index dff85d27..c0502ff6 100644 --- a/src/main/resources/Guilds/branches.yml +++ b/src/main/resources/Guilds/branches.yml @@ -17,7 +17,6 @@ bureaucracy: - trade_power 1 0.5 - production 4 0.5 - trade_upkeep 0 0.03 - - infrastructure 0 0.1 - prestige 0 5 - prestige_bonus 0 0.5 guild_halls: @@ -86,26 +85,6 @@ supply_lines: - hub_upkeep 1 0.5 - trade_upkeep 0 0.01 - prestige 0 5 -infrastructure: - name: "#86d1b0Infrastructure" - icon: "rail.0" - group: 3 - description: - - "#86d1b0Infrastructure #d4c9aeimproves poor" - - "#d4c9aeland in the realm for every guild," - - "#d4c9aestarting at the capital. Hubs come" - - "#d4c9aemore slowly; each level costs daily upkeep." - allowed-types: - - realm - modifiers: - - infrastructure 0 2 - - infrastructure_upkeep 0 1 - - hub_limit 2 0.25 - - hub_trade 0 0.05 - - hub_production 0 0.08 - - hub_upkeep 1 0.5 - - trade_upkeep 0 0.01 - - prestige 0 5 counting_houses: name: "#a9744fCounting Houses" icon: "chest_minecart.0" diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 8574295d..474b544c 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -190,18 +190,6 @@ elevation-size-multiplier: 1.0 elevation-exponent: 1.1 eviction-multiplier: 2.0 -# Infrastructure closes the gap from raw land terrain to target at full strength. -infrastructure: - full: 20 - target: 0.75 - wilderness-spread: 0.25 - spread-floor: 0.5 - station: 10 - port: 10 - airport: 5 - track: 10 - track-refresh-seconds: 300 - terrain-modifiers: - FARMLAND 0.95 - PLAINS 0.85 diff --git a/src/test/java/net/tfminecraft/simplefactions/guild/GuildSavedInfrastructureBranchTest.java b/src/test/java/net/tfminecraft/simplefactions/guild/GuildSavedInfrastructureBranchTest.java new file mode 100644 index 00000000..2c6ff662 --- /dev/null +++ b/src/test/java/net/tfminecraft/simplefactions/guild/GuildSavedInfrastructureBranchTest.java @@ -0,0 +1,107 @@ +package net.tfminecraft.simplefactions.guild; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockConstruction; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.when; + +import java.io.File; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.logging.Logger; + +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.World; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BannerMeta; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.mockito.MockedConstruction; +import org.mockito.MockedStatic; + +import net.tfminecraft.simplefactions.database.GuildData; +import net.tfminecraft.simplefactions.database.JsonUtil; +import net.tfminecraft.simplefactions.guild.branch.Branch; +import net.tfminecraft.simplefactions.guild.upgrade.Upgrade; +import net.tfminecraft.simplefactions.loaders.BranchLoader; +import net.tfminecraft.simplefactions.loaders.GuildLoader; +import net.tfminecraft.simplefactions.loaders.UpgradeLoader; +import net.tfminecraft.simplefactions.objects.Faction; + +class GuildSavedInfrastructureBranchTest { + private final Map savedBranches = new HashMap<>(BranchLoader.map); + private final Map savedTypes = new HashMap<>(GuildLoader.map); + private final Map savedUpgrades = new LinkedHashMap<>(UpgradeLoader.map); + + @AfterEach + void restore() { + BranchLoader.map.clear(); + BranchLoader.map.putAll(savedBranches); + GuildLoader.map.clear(); + GuildLoader.map.putAll(savedTypes); + UpgradeLoader.map.clear(); + UpgradeLoader.map.putAll(savedUpgrades); + } + + @Test + void aSavedInfrastructureBranchIsSkipped() { + loadBundledBranches(); + GuildData data = JsonUtil.GSON.fromJson(""" + { + "id": "realm-guild", + "name": "The Realm", + "leader": "Ada", + "type": "realm", + "capital": 4, + "banner": ["white"], + "wealth modifiers": [], + "branches": [ + {"id": "infrastructure", "level": 4}, + {"id": "bureaucracy", "level": 2} + ] + } + """, GuildData.class); + World world = mock(World.class); + when(world.getChunkAt(0, 0)).thenReturn(mock(Chunk.class)); + + try (MockedStatic bukkit = mockStatic(Bukkit.class); + MockedConstruction items = mockConstruction(ItemStack.class, (mock, context) -> + when(mock.getItemMeta()).thenReturn(mock(BannerMeta.class)))) { + bukkit.when(() -> Bukkit.getWorld(nullable(String.class))).thenReturn(world); + bukkit.when(Bukkit::getLogger).thenReturn(mock(Logger.class)); + + Guild guild = new Guild(data, mock(Faction.class)); + + assertEquals("realm-guild", guild.getId()); + assertNull(guild.getBranch("infrastructure")); + Branch bureaucracy = guild.getBranch("bureaucracy"); + assertNotNull(bureaucracy); + assertEquals(2, bureaucracy.getLevel()); + assertEquals(1, items.constructed().size()); + } + } + + private static void loadBundledBranches() { + YamlConfiguration types = new YamlConfiguration(); + types.set("guild.name", "Guild"); + types.set("realm.name", "Realm"); + types.set("realm.base", true); + GuildLoader.map.clear(); + GuildLoader.map.put("guild", new GuildType("guild", types.getConfigurationSection("guild"))); + GuildLoader.map.put("realm", new GuildType("realm", types.getConfigurationSection("realm"))); + YamlConfiguration config = YamlConfiguration.loadConfiguration( + new File("src/main/resources/Guilds/branches.yml")); + BranchLoader.map.clear(); + UpgradeLoader.map.clear(); + for (String key : config.getKeys(false)) { + BranchLoader.map.put(key, new Branch(key, config.getConfigurationSection(key))); + } + } +} diff --git a/src/test/java/net/tfminecraft/simplefactions/guild/hub/InfrastructureMenuCopyTest.java b/src/test/java/net/tfminecraft/simplefactions/guild/hub/InfrastructureMenuCopyTest.java deleted file mode 100644 index 38c3a91a..00000000 --- a/src/test/java/net/tfminecraft/simplefactions/guild/hub/InfrastructureMenuCopyTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package net.tfminecraft.simplefactions.guild.hub; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.List; - -import org.junit.jupiter.api.Test; - -import net.tfminecraft.simplefactions.guild.hub.InfrastructurePreview.InstallationPreview; - -class InfrastructureMenuCopyTest { - @Test - void headlineUsesTheCachedDailyFigure() { - assertEquals( - "§7Infrastructure is worth about +45 a day to your realm", - InfrastructureMenuCopy.headline(45)); - assertEquals( - "§7Infrastructure is worth about -3 a day to your realm", - InfrastructureMenuCopy.headline(-3)); - assertEquals( - "§7Infrastructure worth is worked out once a day.", - InfrastructureMenuCopy.headlineUnknown()); - } - - @Test - void installationPreviewNamesInfrastructureIncomeAndUpkeep() { - assertEquals( - List.of( - "§a+10 infrastructure here", - "§7about +6 a day for your realm", - "§7upkeep 5"), - InfrastructureMenuCopy.installationPreview(new InstallationPreview(10, 6, 5))); - assertEquals( - List.of( - "§7This adds no infrastructure here", - "§7about +0 a day for your realm", - "§7upkeep 30"), - InfrastructureMenuCopy.installationPreview(new InstallationPreview(0, 0, 30))); - assertTrue(InfrastructureMenuCopy.installationPreview(null).get(0).contains("Working out")); - } -} diff --git a/src/test/java/net/tfminecraft/simplefactions/guild/hub/SupplyHubServiceTest.java b/src/test/java/net/tfminecraft/simplefactions/guild/hub/SupplyHubServiceTest.java index 5e625db5..fd2effb5 100644 --- a/src/test/java/net/tfminecraft/simplefactions/guild/hub/SupplyHubServiceTest.java +++ b/src/test/java/net/tfminecraft/simplefactions/guild/hub/SupplyHubServiceTest.java @@ -525,28 +525,6 @@ void supplyLinesHubLimitAddsOneHubEveryTwoLevels() { } } - @Test - void ledger_infrastructureUpkeepIsShownAndSettledWithoutShedding() { - Guild guild = mock(Guild.class); - Faction faction = mock(Faction.class); - Bank bank = mock(Bank.class); - when(bank.getWealth()).thenReturn(0.0); - when(guild.getModifier(GuildModifier.INFRASTRUCTURE_UPKEEP)).thenReturn(4.0); - Ledger ledger = ledger(faction, guild, bank); - - assertTrue(Cashflow.INFRASTRUCTURE_UPKEEP.getDisplay().contains("Infrastructure")); - assertEquals(-4.0, ledger.getIncome(Cashflow.INFRASTRUCTURE_UPKEEP), 1e-9); - assertEquals(-4.0, ledger.getNetIncome(), 1e-9); - DailyGuildTransfers buffer = new DailyGuildTransfers(); - ledger.populateDailyTransfers(buffer); - assertEquals(-4.0, buffer.getExternalDeltas().get(guild), 1e-9); - - Guild withoutInfrastructure = mock(Guild.class); - when(withoutInfrastructure.getModifier(GuildModifier.INFRASTRUCTURE_UPKEEP)).thenReturn(0.0); - Ledger noInfrastructureLedger = ledger(faction, withoutInfrastructure, bank); - assertEquals(0.0, noInfrastructureLedger.getIncome(Cashflow.INFRASTRUCTURE_UPKEEP), 1e-9); - } - @Test void ledger_removesEveryHubWhenNoneCanBePaid() { Guild guild = mock(Guild.class); diff --git a/src/test/java/net/tfminecraft/simplefactions/guild/income/BranchIncomePreviewTest.java b/src/test/java/net/tfminecraft/simplefactions/guild/income/BranchIncomePreviewTest.java index 6b60bc2d..4592b7b6 100644 --- a/src/test/java/net/tfminecraft/simplefactions/guild/income/BranchIncomePreviewTest.java +++ b/src/test/java/net/tfminecraft/simplefactions/guild/income/BranchIncomePreviewTest.java @@ -1,7 +1,6 @@ package net.tfminecraft.simplefactions.guild.income; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; @@ -41,7 +40,6 @@ import net.tfminecraft.simplefactions.managers.ProvinceManager; import net.tfminecraft.simplefactions.map.provinces.Province; import net.tfminecraft.simplefactions.objects.Faction; -import net.tfminecraft.simplefactions.objects.handler.GuildHandler; class BranchIncomePreviewTest { private final List savedFactions = new ArrayList<>(); @@ -201,70 +199,4 @@ void hubTradeBranchNoLongerChangesIncome() { assertEquals(0, live.previewUpgradeIncomeExact(guild, supplyLines)); assertEquals(0, supplyLines.getLevel()); } - - @Test - void branchPreviewIncludesInfrastructureUpkeepChange() { - YamlConfiguration yaml = new YamlConfiguration(); - yaml.set("group", 3); - yaml.set("modifiers", List.of("INFRASTRUCTURE_UPKEEP 0 1")); - Branch infrastructure = new Branch(new Branch("infrastructure", yaml), 2); - when(guild.getModifier(GuildModifier.INFRASTRUCTURE_UPKEEP)).thenReturn(2.0); - - assertEquals(-1.0, live.previewUpgradeIncomeExact(guild, infrastructure)); - assertEquals(1.0, live.previewDowngradeIncomeExact(guild, infrastructure)); - assertEquals(2, infrastructure.getLevel()); - assertFalse(BranchIncomePreview.showsRealm(guild, infrastructure)); - } - - @Test - void infrastructureOnTheRealmGuildCountsEveryGuild() { - Cache.tradeCarry.put(Terrain.PLAINS, 0.4); - Guild realmGuild = guild("realm", true); - Guild other = guild("fields-two", false); - GuildHandler handler = mock(GuildHandler.class); - when(handler.getGuilds()).thenReturn(List.of(realmGuild)); - when(faction.getId()).thenReturn("home"); - when(faction.getGuildHandler()).thenReturn(handler); - FactionManager.factions.add(faction); - - YamlConfiguration yaml = new YamlConfiguration(); - yaml.set("group", 3); - yaml.set("modifiers", List.of("INFRASTRUCTURE 0 20")); - Branch infrastructure = new Branch(new Branch("infrastructure", yaml), 0); - assertTrue(BranchIncomePreview.showsRealm(realmGuild, infrastructure)); - assertFalse(BranchIncomePreview.showsRealm(other, infrastructure)); - assertFalse(BranchIncomePreview.showsRealm(realmGuild, branch)); - - BranchIncomePreview.Prepared prepared = BranchIncomePreview.prepare(live); - Map current = BranchIncomePreview.modifiers(realmGuild); - Map raised = BranchIncomePreview.adjust(current, infrastructure, 0, 1); - double alone = BranchIncomePreview.estimateRealm( - prepared, realmGuild, current, raised, - BranchIncomePreview.guildsNow(), BranchIncomePreview.factionsNow()); - when(handler.getGuilds()).thenReturn(List.of(realmGuild, other)); - double both = BranchIncomePreview.estimateRealm( - prepared, realmGuild, current, raised, - BranchIncomePreview.guildsNow(), BranchIncomePreview.factionsNow()); - - assertTrue(alone > 0, "alone " + alone); - assertTrue(both > alone, "both " + both + " alone " + alone); - assertEquals(0, infrastructure.getLevel()); - } - - private Guild guild(String id, boolean base) { - Guild created = mock(Guild.class); - when(created.getId()).thenReturn(id); - when(created.isBase()).thenReturn(base); - when(created.hasCapital()).thenReturn(true); - when(created.getCapital()).thenReturn(capital.getId()); - when(created.getFaction()).thenReturn(faction); - when(created.getModifier(any())).thenAnswer(invocation -> switch ((GuildModifier) invocation.getArgument(0)) { - case TRADE_POWER -> 8.0; - case TRADE_CARRY -> 1.2; - case PRODUCTION -> 6.0; - case TRADE_UPKEEP -> 0.05; - default -> 0.0; - }); - return created; - } } diff --git a/src/test/java/net/tfminecraft/simplefactions/loaders/ConfigLoaderInfrastructureTest.java b/src/test/java/net/tfminecraft/simplefactions/loaders/ConfigLoaderInfrastructureTest.java deleted file mode 100644 index 2f96c2f6..00000000 --- a/src/test/java/net/tfminecraft/simplefactions/loaders/ConfigLoaderInfrastructureTest.java +++ /dev/null @@ -1,130 +0,0 @@ -package net.tfminecraft.simplefactions.loaders; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -import net.tfminecraft.simplefactions.Cache; - -class ConfigLoaderInfrastructureTest { - @TempDir - Path tempDir; - private final double[] previous = values(); - - @AfterEach - void restore() { - Cache.infrastructureFull = previous[0]; - Cache.infrastructureTarget = previous[1]; - Cache.infrastructureWildernessSpread = previous[2]; - Cache.infrastructureSpreadFloor = previous[3]; - Cache.infrastructureStation = previous[4]; - Cache.infrastructurePort = previous[5]; - Cache.infrastructureAirport = previous[6]; - Cache.infrastructureTrack = previous[7]; - Cache.infrastructureTrackRefreshSeconds = (int) previous[8]; - } - - @Test - void missingSectionUsesDefaultsAndResetsPreviousSettings() throws IOException { - load(""" - infrastructure: - full: 30 - target: 0.80 - wilderness-spread: 0.10 - spread-floor: 0.25 - station: 12 - port: 8 - airport: 4 - """); - load("enable-map: false\n"); - - assertValues(20, 0.75, 0.25, 0.5, 10, 10, 5, 10, 300); - } - - @Test - void missingKeysUseDefaultsIndependently() throws IOException { - load(""" - infrastructure: - full: 30 - """); - - assertValues(30, 0.75, 0.25, 0.5, 10, 10, 5, 10, 300); - } - - @Test - void configuredKeysAreReadIntoCache() throws IOException { - load(""" - infrastructure: - full: 30 - target: 0.80 - wilderness-spread: 0.10 - spread-floor: 0.25 - station: 12 - port: 8 - airport: 4 - track: 17 - track-refresh-seconds: 45 - """); - - assertValues(30, 0.80, 0.10, 0.25, 12, 8, 4, 17, 45); - } - - @Test - void zeroFullUsesDefault() throws IOException { - load("infrastructure:\n full: 0\n"); - - assertEquals(20, Cache.infrastructureFull, 1e-9); - } - - @Test - void negativeFullUsesDefault() throws IOException { - load("infrastructure:\n full: -5\n"); - - assertEquals(20, Cache.infrastructureFull, 1e-9); - } - - @Test - void zeroSpreadFloorUsesDefault() throws IOException { - load("infrastructure:\n spread-floor: 0\n"); - - assertEquals(0.5, Cache.infrastructureSpreadFloor, 1e-9); - } - - @Test - void negativeSpreadFloorUsesDefault() throws IOException { - load("infrastructure:\n spread-floor: -0.25\n"); - - assertEquals(0.5, Cache.infrastructureSpreadFloor, 1e-9); - } - - @Test - void positiveSpreadFloorIsKept() throws IOException { - load("infrastructure:\n spread-floor: 0.25\n"); - - assertEquals(0.25, Cache.infrastructureSpreadFloor, 1e-9); - } - - private void load(String yaml) throws IOException { - Path file = tempDir.resolve("config.yml"); - Files.writeString(file, yaml); - new ConfigLoader().loadConfig(file.toFile()); - } - - private static double[] values() { - return new double[] {Cache.infrastructureFull, Cache.infrastructureTarget, - Cache.infrastructureWildernessSpread, Cache.infrastructureSpreadFloor, - Cache.infrastructureStation, Cache.infrastructurePort, Cache.infrastructureAirport, - Cache.infrastructureTrack, Cache.infrastructureTrackRefreshSeconds}; - } - - private static void assertValues(double... expected) { - double[] actual = values(); - for (int i = 0; i < expected.length; i++) assertEquals(expected[i], actual[i], 1e-9); - } -} diff --git a/src/test/java/net/tfminecraft/simplefactions/loaders/ProvinceLoaderInfrastructureTest.java b/src/test/java/net/tfminecraft/simplefactions/loaders/ProvinceLoaderInfrastructureTest.java new file mode 100644 index 00000000..7ab3bae4 --- /dev/null +++ b/src/test/java/net/tfminecraft/simplefactions/loaders/ProvinceLoaderInfrastructureTest.java @@ -0,0 +1,37 @@ +package net.tfminecraft.simplefactions.loaders; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import net.tfminecraft.simplefactions.enums.Terrain; +import net.tfminecraft.simplefactions.map.provinces.Province; + +class ProvinceLoaderInfrastructureTest { + @TempDir + Path dir; + + @Test + void aSavedInfrastructureSegmentDoesNotStopTheProvinceLoading() throws Exception { + Path provinces = dir.resolve("provinces.txt"); + Path neighbours = dir.resolve("neighbours.json"); + Files.writeString(provinces, "1 = 10,64,20;bog;40;12\n2 = 30,64,40;plains;7\n"); + Files.writeString(neighbours, "{\"1\":[2],\"2\":[1]}"); + + Map loaded = new ProvinceLoader().loadProvinces( + provinces.toFile(), neighbours.toFile()); + + assertEquals(Terrain.BOG, loaded.get(1).getTerrain()); + assertEquals(40, loaded.get(1).getFertility()); + assertEquals(10, loaded.get(1).getCenterX()); + assertEquals(20, loaded.get(1).getCenterZ()); + assertEquals(Terrain.PLAINS, loaded.get(2).getTerrain()); + assertEquals(7, loaded.get(2).getFertility()); + assertEquals(1, loaded.get(1).getNeighbours().size()); + } +} diff --git a/src/test/java/net/tfminecraft/simplefactions/loaders/SupplyHubBranchesTest.java b/src/test/java/net/tfminecraft/simplefactions/loaders/SupplyHubBranchesTest.java index 46373845..df0855e4 100644 --- a/src/test/java/net/tfminecraft/simplefactions/loaders/SupplyHubBranchesTest.java +++ b/src/test/java/net/tfminecraft/simplefactions/loaders/SupplyHubBranchesTest.java @@ -60,11 +60,11 @@ void bundledBranchesLoadForGuildsAndRealms() { Branch freightRealm = BranchLoader.getByGroup(realmType, 4); assertNotNull(supplyGuild); - assertNotNull(supplyRealm); + assertNull(supplyRealm); assertNotNull(freightGuild); assertNotNull(freightRealm); assertEquals("supply_lines", supplyGuild.getId()); - assertEquals("infrastructure", supplyRealm.getId()); + assertNull(BranchLoader.getByString("infrastructure")); assertEquals("counting_houses", freightRealm.getId()); assertEquals(2.0, supplyGuild.getModifier(GuildModifier.HUB_LIMIT).getBase()); assertEquals(0.5, supplyGuild.getModifier(GuildModifier.HUB_LIMIT).getPerLevel()); @@ -73,12 +73,7 @@ void bundledBranchesLoadForGuildsAndRealms() { assertEquals(-0.01, freightRealm.getModifier(GuildModifier.TRADE_UPKEEP).getPerLevel()); assertEquals(1.0, supplyGuild.getModifier(GuildModifier.HUB_UPKEEP).getBase()); assertEquals(0.5, supplyGuild.getModifier(GuildModifier.HUB_UPKEEP).getPerLevel()); - Branch infrastructure = new Branch(BranchLoader.getByString("infrastructure"), 10); - assertEquals(20.0, infrastructure.getAmount(GuildModifier.INFRASTRUCTURE)); - assertEquals(10.0, infrastructure.getAmount(GuildModifier.INFRASTRUCTURE_UPKEEP)); - Branch bureaucracy = new Branch(BranchLoader.getByString("bureaucracy"), 5); - assertEquals(20.5, infrastructure.getAmount(GuildModifier.INFRASTRUCTURE) - + bureaucracy.getAmount(GuildModifier.INFRASTRUCTURE)); + assertNotNull(BranchLoader.getByString("bureaucracy")); Branch storehouses = new Branch(BranchLoader.getByString("storehouses"), 3); Branch supplyLines = new Branch(BranchLoader.getByString("supply_lines"), 4); assertEquals(0.70, storehouses.getAmount(GuildModifier.TRADE_CARRY)); @@ -94,7 +89,7 @@ void bundledBranchesLoadForGuildsAndRealms() { } @Test - void savedBranchesMoveToTheAllowedBranchAtTheSameLevel() { + void savedSupplyLinesStayWhenTheRealmHasNoBranchInThatGroup() { loadBundledBranches(); Branch supplyLines = new Branch(BranchLoader.getByString("supply_lines"), 3); Map realmBranches = new HashMap<>(Map.of(3, supplyLines)); @@ -102,7 +97,7 @@ void savedBranchesMoveToTheAllowedBranchAtTheSameLevel() { BranchLoader.replaceDisallowedBranches(realmBranches, GuildLoader.getByString("realm")); BranchLoader.replaceDisallowedBranches(normalBranches, GuildLoader.getByString("guild")); - assertEquals("infrastructure", realmBranches.get(3).getId()); + assertEquals("supply_lines", realmBranches.get(3).getId()); assertEquals(3, realmBranches.get(3).getLevel()); assertEquals("supply_lines", normalBranches.get(3).getId()); assertEquals(3, normalBranches.get(3).getLevel()); diff --git a/src/test/java/net/tfminecraft/simplefactions/managers/inventory/GuildCreatorIncomeLineTest.java b/src/test/java/net/tfminecraft/simplefactions/managers/inventory/GuildCreatorIncomeLineTest.java deleted file mode 100644 index ad54ef36..00000000 --- a/src/test/java/net/tfminecraft/simplefactions/managers/inventory/GuildCreatorIncomeLineTest.java +++ /dev/null @@ -1,22 +0,0 @@ -package net.tfminecraft.simplefactions.managers.inventory; - -import static org.junit.jupiter.api.Assertions.assertTrue; - -import org.junit.jupiter.api.Test; - -class GuildCreatorIncomeLineTest { - @Test - void aRealmBranchNamesTheWholeRealm() { - GuildCreator creator = new GuildCreator(); - String realm = creator.incomeChangeLine(12.5, true); - String guild = creator.incomeChangeLine(12.5, false); - String waiting = creator.incomeChangeLine(null, true); - - assertTrue(realm.contains("Estimated Realm Income Change"), realm); - assertTrue(realm.contains("+12.50"), realm); - assertTrue(guild.contains("Estimated Income Change"), guild); - assertTrue(!guild.contains("Realm"), guild); - assertTrue(waiting.contains("Estimated Realm Income Change"), waiting); - assertTrue(waiting.contains("Calculating"), waiting); - } -} diff --git a/src/test/java/net/tfminecraft/simplefactions/map/CompilerProvinceExportTest.java b/src/test/java/net/tfminecraft/simplefactions/map/CompilerProvinceExportTest.java index 82659bd8..27c5e03a 100644 --- a/src/test/java/net/tfminecraft/simplefactions/map/CompilerProvinceExportTest.java +++ b/src/test/java/net/tfminecraft/simplefactions/map/CompilerProvinceExportTest.java @@ -2,109 +2,26 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; -import java.util.HashMap; -import java.util.Map; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import com.google.gson.JsonObject; -import net.tfminecraft.simplefactions.Cache; -import net.tfminecraft.simplefactions.enums.Terrain; import net.tfminecraft.simplefactions.guild.Guild; import net.tfminecraft.simplefactions.map.provinces.Province; import net.tfminecraft.simplefactions.map.provinces.ProvinceDataEntry; class CompilerProvinceExportTest { - private final Map previousCarry = new HashMap<>(Cache.tradeCarry); - private final double previousFull = Cache.infrastructureFull; - private final double previousTarget = Cache.infrastructureTarget; - - @BeforeEach - void setUp() { - Cache.infrastructureFull = 20; - Cache.infrastructureTarget = 0.75; - Cache.tradeCarry.clear(); - Cache.tradeCarry.put(Terrain.BOG, 0.40); - Cache.tradeCarry.put(Terrain.PLAINS, 0.75); - Cache.tradeCarry.put(Terrain.SEA, 0.60); - Cache.tradeCarry.put(Terrain.WATER, 0.75); - } - - @AfterEach - void restore() { - Cache.infrastructureFull = previousFull; - Cache.infrastructureTarget = previousTarget; - Cache.tradeCarry.clear(); - Cache.tradeCarry.putAll(previousCarry); - } - - @Test - void bogWithInfrastructureExportsFillAndEffectiveTerrain() { - Province province = new Province(1, "bog", 0); - province.setInfrastructure(12); - - JsonObject json = Compiler.provinceToJson(province, null); - - assertEquals("bog", json.get("terrain").getAsString()); - assertEquals(0.40, json.get("terrain_value").getAsDouble()); - assertEquals(12, json.get("infrastructure").getAsDouble()); - assertEquals(0.60, json.get("infrastructure_fill").getAsDouble()); - assertEquals(0.61, json.get("effective_terrain").getAsDouble()); - } - @Test - void terrainValueIsNotRounded() { - Cache.tradeCarry.put(Terrain.BOG, 0.445); - - JsonObject json = Compiler.provinceToJson(new Province(1, "bog", 0), null); - - assertEquals(0.445, json.get("terrain_value").getAsDouble()); - } - - @Test - void invalidInfrastructureFullOmitsInfrastructureFields() { - Cache.infrastructureFull = -5; - Province province = new Province(1, "bog", 0); - province.setInfrastructure(12); - - JsonObject json = Compiler.provinceToJson(province, null); - - assertFalse(json.has("infrastructure")); - assertFalse(json.has("infrastructure_fill")); - } - - @Test - void bogWithoutInfrastructureOmitsInfrastructureFields() { - JsonObject json = Compiler.provinceToJson(new Province(1, "bog", 0), null); - - assertEquals(0.40, json.get("effective_terrain").getAsDouble()); - assertFalse(json.has("infrastructure")); - assertFalse(json.has("infrastructure_fill")); - } - - @Test - void infrastructureDoesNotRaisePlainsAboveItsTerrainValue() { - Province province = new Province(1, "plains", 0); - province.setInfrastructure(20); - - assertEquals(0.75, Compiler.provinceToJson(province, null).get("effective_terrain").getAsDouble()); - } - - @Test - void seaAndWaterOmitAllNewTerrainFields() { - for (String terrain : new String[] {"sea", "water"}) { + void provincesOmitInfrastructureAndEffectiveTerrain() { + for (String terrain : new String[] {"bog", "plains", "sea", "water"}) { JsonObject json = Compiler.provinceToJson(new Province(1, terrain, 0), null); - assertFalse(json.has("terrain")); - assertFalse(json.has("terrain_value")); assertFalse(json.has("infrastructure")); assertFalse(json.has("infrastructure_fill")); assertFalse(json.has("effective_terrain")); + assertFalse(json.has("terrain")); + assertFalse(json.has("terrain_value")); } } @@ -122,6 +39,6 @@ void tradeObjectAndExistingFieldOrderArePreserved() { assertEquals("prosperity", json.keySet().toArray()[1]); assertEquals("occupied_by", json.keySet().toArray()[2]); assertEquals("trade", json.keySet().toArray()[3]); - assertTrue(json.has("effective_terrain")); + assertEquals(4, json.keySet().size()); } } diff --git a/src/test/java/net/tfminecraft/simplefactions/map/infra/EffectiveTerrainTest.java b/src/test/java/net/tfminecraft/simplefactions/map/infra/EffectiveTerrainTest.java deleted file mode 100644 index d791740c..00000000 --- a/src/test/java/net/tfminecraft/simplefactions/map/infra/EffectiveTerrainTest.java +++ /dev/null @@ -1,39 +0,0 @@ -package net.tfminecraft.simplefactions.map.infra; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.junit.jupiter.api.Test; - -class EffectiveTerrainTest { - @Test - void zeroInfrastructureLeavesRawTerrainAlone() { - for (double terrain : new double[] {0.80, 0.75, 0.40, 0.30}) { - assertEquals(terrain, EffectiveTerrain.calculate(terrain, 0, 20, 0.75, 1)); - } - } - - @Test - void fullInfrastructureFillsTheGapAndStopsAtFull() { - assertEquals(0.75, EffectiveTerrain.calculate(0.40, 20, 20, 0.75, 1), 1e-9); - assertEquals(0.75, EffectiveTerrain.calculate(0.40, 40, 20, 0.75, 1), 1e-9); - } - - @Test - void halfInfrastructureFillsHalfTheGap() { - assertEquals(0.575, EffectiveTerrain.calculate(0.40, 10, 20, 0.75, 1), 1e-9); - } - - @Test - void accessScalesTheGap() { - assertEquals(0.575, EffectiveTerrain.calculate(0.40, 20, 20, 0.75, 0.5), 1e-9); - assertEquals(0.40, EffectiveTerrain.calculate(0.40, 20, 20, 0.75, 0), 1e-9); - } - - @Test - void terrainAtOrAboveTheTargetIsUnchangedAtAnyFill() { - for (double infrastructure : new double[] {0, 10, 20, 40}) { - assertEquals(0.80, EffectiveTerrain.calculate(0.80, infrastructure, 20, 0.75, 1)); - assertEquals(0.75, EffectiveTerrain.calculate(0.75, infrastructure, 20, 0.75, 1)); - } - } -} diff --git a/src/test/java/net/tfminecraft/simplefactions/map/infra/InfrastructureSourcesTest.java b/src/test/java/net/tfminecraft/simplefactions/map/infra/InfrastructureSourcesTest.java deleted file mode 100644 index 5612fc9a..00000000 --- a/src/test/java/net/tfminecraft/simplefactions/map/infra/InfrastructureSourcesTest.java +++ /dev/null @@ -1,175 +0,0 @@ -package net.tfminecraft.simplefactions.map.infra; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Test; - -import net.tfminecraft.simplefactions.Cache; -import net.tfminecraft.simplefactions.enums.GuildModifier; -import net.tfminecraft.simplefactions.guild.Guild; -import net.tfminecraft.simplefactions.guild.GuildModifierOverride; -import net.tfminecraft.simplefactions.installation.Installation; -import net.tfminecraft.simplefactions.installation.InstallationKind; -import net.tfminecraft.simplefactions.installation.handler.InstallationHandler; -import net.tfminecraft.simplefactions.map.provinces.Province; -import net.tfminecraft.simplefactions.objects.Faction; - -class InfrastructureSourcesTest { - private final double station = Cache.infrastructureStation; - private final double port = Cache.infrastructurePort; - private final double airport = Cache.infrastructureAirport; - private final double track = Cache.infrastructureTrack; - - @AfterEach - void restore() { - GuildModifierOverride.clear(); - Cache.infrastructureStation = station; - Cache.infrastructurePort = port; - Cache.infrastructureAirport = airport; - Cache.infrastructureTrack = track; - } - - @Test - void realmCapitalUsesTheResolvedModifierOnce() { - Guild guild = guild(true, 1, 12.5); - Map sources = InfrastructureSources.collect( - Map.of(1, province(1, "forest")), List.of(guild), List.of(), Set.of()); - - assertEquals(12.5, sources.get(1)); - verify(guild, times(1)).getModifier(GuildModifier.INFRASTRUCTURE); - assertTrue(GuildModifier.INFRASTRUCTURE.isPositive()); - assertEquals(GuildModifier.PRODUCTION.scalesWithInactivity(), GuildModifier.INFRASTRUCTURE.scalesWithInactivity()); - } - - @Test - void capitalUsesPreviewOverrideInsteadOfTheLiveModifier() { - Guild guild = guild(true, 1, 12.5); - GuildModifierOverride.use(guild, Map.of(GuildModifier.INFRASTRUCTURE, 17.0)); - Map sources = InfrastructureSources.collect( - Map.of(1, province(1, "forest")), List.of(guild), List.of(), Set.of()); - - assertEquals(17, sources.get(1)); - verify(guild, never()).getModifier(GuildModifier.INFRASTRUCTURE); - } - - @Test - void nonBaseGuildsAndGuildsWithoutCapitalsAddNothing() { - Guild regular = guild(false, 1, 12.5); - Guild noCapital = guild(true, 1, 12.5); - when(noCapital.hasCapital()).thenReturn(false); - - assertTrue(InfrastructureSources.collect(Map.of(1, province(1, "forest")), - List.of(regular, noCapital), List.of(), Set.of()).isEmpty()); - verify(regular, never()).getModifier(GuildModifier.INFRASTRUCTURE); - verify(noCapital, never()).getModifier(GuildModifier.INFRASTRUCTURE); - } - - @Test - void installationsUseConfigAmountsWithoutScalingByLevelAndFortsAddNothing() { - Cache.infrastructureStation = 7; - Cache.infrastructurePort = 11; - Cache.infrastructureAirport = 3; - Installation station = installation(InstallationKind.TRAIN_STATION, 1); - Installation port = installation(InstallationKind.PORT, 2); - Installation airport = installation(InstallationKind.AIRPORT, 3); - Installation fort = installation(InstallationKind.FORT, 4); - Map sources = InfrastructureSources.collect(Map.of( - 1, province(1, "forest"), 2, province(2, "forest"), - 3, province(3, "forest"), 4, province(4, "forest")), List.of(), - List.of(faction(station, port, airport, fort)), Set.of()); - - assertEquals(Map.of(1, 7.0, 2, 11.0, 3, 3.0), sources); - verify(station, never()).getLevel(); - verify(port, never()).getLevel(); - verify(airport, never()).getLevel(); - } - - @Test - void sourcesInOneProvinceAddBeforeTheySpread() { - Cache.infrastructureStation = 10; - Guild guild = guild(true, 1, 10); - Map sources = InfrastructureSources.collect(Map.of( - 1, province(1, "forest"), 2, province(2, "plains")), List.of(guild), - List.of(faction(installation(InstallationKind.TRAIN_STATION, 1))), Set.of()); - Map result = InfrastructureSpread.spread(Map.of( - 1, new InfrastructureSpread.Node(0.6, true, "realm", List.of(2)), - 2, new InfrastructureSpread.Node(0.75, true, "realm", List.of(1))), sources, 0.25, 0.5); - - assertEquals(20, sources.get(1)); - assertEquals(15, result.get(2).amount()); - } - - @Test - void sourcesOutsideTheManagerAndOnSeaOrWaterAreIgnored() { - Map sources = InfrastructureSources.collect(Map.of( - 1, province(1, "sea"), 2, province(2, "water")), - List.of(guild(true, 1, 10), guild(true, 2, 10), guild(true, 3, 10)), - List.of(faction(installation(InstallationKind.PORT, 1), - installation(InstallationKind.TRAIN_STATION, 2), - installation(InstallationKind.AIRPORT, 3))), Set.of()); - - assertTrue(sources.isEmpty()); - } - - @Test - void trackProvincesAddOnceAndCombineWithOtherSources() { - Cache.infrastructureTrack = 10; - Map sources = InfrastructureSources.collect(Map.of( - 1, province(1, "forest"), 2, province(2, "sea"), 3, province(3, "plains")), - List.of(), List.of(faction(installation(InstallationKind.TRAIN_STATION, 1))), Set.of(1, 2, 3)); - - assertEquals(Map.of(1, 20.0, 3, 10.0), sources); - } - - @Test - void trackProvinceSourceSpreadsOnlyThroughUnownedLand() { - Map provinces = Map.of(1, province(1, "plains"), 2, province(2, "plains")); - Map sources = InfrastructureSources.collect(provinces, List.of(), List.of(), Set.of(1)); - Map result = InfrastructureSpread.spread(Map.of( - 1, new InfrastructureSpread.Node(0.75, true, null, List.of(2)), - 2, new InfrastructureSpread.Node(0.75, true, "realm", List.of(1))), sources, 0.25, 0.5); - - assertEquals(10, result.get(1).amount()); - assertTrue(!result.containsKey(2)); - } - - private static Province province(int id, String terrain) { - return new Province(id, terrain, 0); - } - - private static Guild guild(boolean base, int capital, double amount) { - Guild guild = mock(Guild.class); - when(guild.isBase()).thenReturn(base); - when(guild.hasCapital()).thenReturn(true); - when(guild.getCapital()).thenReturn(capital); - when(guild.getModifier(GuildModifier.INFRASTRUCTURE)).thenReturn(amount); - return guild; - } - - private static Installation installation(InstallationKind kind, int province) { - Installation installation = mock(Installation.class); - when(installation.getKind()).thenReturn(kind); - when(installation.getProvince()).thenReturn(province); - when(installation.getLevel()).thenReturn(5); - return installation; - } - - private static Faction faction(Installation... installations) { - Faction faction = mock(Faction.class); - InstallationHandler handler = mock(InstallationHandler.class); - when(faction.getInstallationHandler()).thenReturn(handler); - when(handler.getAll()).thenReturn(List.of(installations)); - return faction; - } -} diff --git a/src/test/java/net/tfminecraft/simplefactions/map/infra/InfrastructureSpreadTest.java b/src/test/java/net/tfminecraft/simplefactions/map/infra/InfrastructureSpreadTest.java deleted file mode 100644 index dc924b7c..00000000 --- a/src/test/java/net/tfminecraft/simplefactions/map/infra/InfrastructureSpreadTest.java +++ /dev/null @@ -1,135 +0,0 @@ -package net.tfminecraft.simplefactions.map.infra; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNull; - -import java.util.List; -import java.util.Map; - -import org.junit.jupiter.api.Test; - -import net.tfminecraft.simplefactions.map.infra.InfrastructureSpread.Arrival; -import net.tfminecraft.simplefactions.map.infra.InfrastructureSpread.Node; - -class InfrastructureSpreadTest { - @Test - void eachHopMultipliesByTheEnteredRawTerrain() { - Map result = spread(Map.of( - 1, land(0.4, "realm", 2), - 2, land(0.75, "realm", 1, 3), - 3, land(0.75, "realm", 2)), Map.of(1, 10.0)); - - assertEquals(7.5, result.get(2).amount(), 1e-9); - assertEquals(5.625, result.get(3).amount(), 1e-9); - assertEquals("realm", result.get(3).origin()); - } - - @Test - void aWorsePathDoesNotReplaceTheBetterArrival() { - Map result = spread(Map.of( - 1, land(0.75, "realm", 2, 3), - 2, land(0.75, "realm", 1, 4), - 3, land(0.4, "realm", 1, 4), - 4, land(0.75, "realm", 2, 3)), Map.of(1, 10.0)); - - assertEquals(5.625, result.get(4).amount(), 1e-9); - } - - @Test - void waterCannotBeEnteredOrUsedAsASource() { - Map result = spread(Map.of( - 1, land(0.75, "realm", 2), - 2, new Node(0.75, false, "realm", List.of(1, 3)), - 3, land(0.75, "realm", 2)), Map.of(1, 10.0, 2, 100.0)); - - assertFalse(result.containsKey(2)); - assertFalse(result.containsKey(3)); - } - - @Test - void anotherRealmBlocksSpread() { - Map result = spread(Map.of( - 1, land(0.75, "home", 2), - 2, land(0.75, "foreign", 1, 3), - 3, land(0.75, "home", 2)), Map.of(1, 10.0)); - - assertFalse(result.containsKey(2)); - assertFalse(result.containsKey(3)); - } - - @Test - void everyUnownedProvinceEnteredGetsTheWildernessPenalty() { - Map graph = Map.of( - 1, land(0.75, "home", 2), - 2, land(0.4, null, 1, 3), - 3, land(0.75, null, 2)); - Map result = InfrastructureSpread.spread(graph, Map.of(1, 10.0), 0.25, 0.1); - - assertEquals(10 * 0.40 * 0.25, result.get(2).amount(), 1e-9); - assertEquals(10 * 0.40 * 0.25 * 0.75 * 0.25, result.get(3).amount(), 1e-9); - assertFalse(spread(graph, Map.of(1, 10.0)).containsKey(3)); - } - - @Test - void unownedSourcesStayInUnownedLand() { - Map result = spread(Map.of( - 1, land(0.75, null, 2, 3), - 2, land(0.75, "realm", 1), - 3, land(0.75, null, 1)), Map.of(1, 10.0)); - - assertFalse(result.containsKey(2)); - assertEquals(1.875, result.get(3).amount(), 1e-9); - assertNull(result.get(3).origin()); - } - - @Test - void ownedSourcesCanReenterTheirRealmFromWilderness() { - Map result = spread(Map.of( - 1, land(0.75, "home", 2), - 2, land(0.4, null, 1, 3, 4), - 3, land(0.75, "home", 2), - 4, land(0.75, "foreign", 2)), Map.of(1, 10.0)); - - assertEquals(0.75, result.get(3).amount(), 1e-9); - assertEquals("home", result.get(3).origin()); - assertFalse(result.containsKey(4)); - } - - @Test - void arrivalsBelowTheFloorStopButAnArrivalAtTheFloorContinues() { - Map result = spread(Map.of( - 1, land(0.75, "realm", 2, 3), - 2, land(0.4, "realm", 1, 4), - 3, land(0.5, "realm", 1, 5), - 4, land(0.75, "realm", 2), - 5, land(1, "realm", 3)), Map.of(1, 1.0)); - - assertFalse(result.containsKey(2)); - assertFalse(result.containsKey(4)); - assertEquals(0.5, result.get(3).amount(), 1e-9); - assertEquals(0.5, result.get(5).amount(), 1e-9); - } - - @Test - void theWinningArrivalKeepsItsOriginAcrossWilderness() { - Map result = spread(Map.of( - 1, land(0.75, "first", 3), - 2, land(0.75, "second", 3), - 3, land(0.75, null, 1, 2, 4, 5), - 4, land(0.75, "first", 3), - 5, land(0.75, "second", 3)), Map.of(1, 10.0, 2, 20.0)); - - assertEquals("second", result.get(3).origin()); - assertFalse(result.containsKey(4)); - assertEquals(2.8125, result.get(5).amount(), 1e-9); - } - - private static Node land(double terrain, String realm, Integer... neighbours) { - return new Node(terrain, true, realm, List.of(neighbours)); - } - - private static Map spread(Map graph, Map sources) { - return InfrastructureSpread.spread(graph, sources, 0.25, 0.5); - } -} diff --git a/src/test/java/net/tfminecraft/simplefactions/map/infra/ProvinceInfrastructureTest.java b/src/test/java/net/tfminecraft/simplefactions/map/infra/ProvinceInfrastructureTest.java deleted file mode 100644 index a112a621..00000000 --- a/src/test/java/net/tfminecraft/simplefactions/map/infra/ProvinceInfrastructureTest.java +++ /dev/null @@ -1,249 +0,0 @@ -package net.tfminecraft.simplefactions.map.infra; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotSame; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockStatic; -import static org.mockito.Mockito.when; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.MockedStatic; - -import net.tfminecraft.simplefactions.Cache; -import net.tfminecraft.simplefactions.enums.GuildModifier; -import net.tfminecraft.simplefactions.enums.Terrain; -import net.tfminecraft.simplefactions.guild.Guild; -import net.tfminecraft.simplefactions.guild.GuildModifierOverride; -import net.tfminecraft.simplefactions.guild.hub.HubNetwork; -import net.tfminecraft.simplefactions.guild.income.EconomicPreview; -import net.tfminecraft.simplefactions.guild.income.TradeBreakdown; -import net.tfminecraft.simplefactions.installation.Installation; -import net.tfminecraft.simplefactions.installation.InstallationKind; -import net.tfminecraft.simplefactions.installation.handler.InstallationHandler; -import net.tfminecraft.simplefactions.managers.FactionManager; -import net.tfminecraft.simplefactions.managers.ProvinceManager; -import net.tfminecraft.simplefactions.managers.TitleManager; -import net.tfminecraft.simplefactions.map.provinces.Province; -import net.tfminecraft.simplefactions.map.provinces.ProvinceDataEntry; -import net.tfminecraft.simplefactions.objects.Faction; - -class ProvinceInfrastructureTest { - private final Map previousCarry = new HashMap<>(Cache.tradeCarry); - private final boolean previousEnabled = Cache.provincesEnabled; - private final double previousFull = Cache.infrastructureFull; - private final double previousTarget = Cache.infrastructureTarget; - private final double previousWilderness = Cache.infrastructureWildernessSpread; - private final double previousFloor = Cache.infrastructureSpreadFloor; - private final double previousStation = Cache.infrastructureStation; - private final double previousMaxUpkeep = Cache.maxTradeUpkeep; - private MockedStatic factions; - private MockedStatic titles; - private MockedStatic hubs; - private Guild guild; - private Faction faction; - - @BeforeEach - void setUp() { - Cache.provincesEnabled = true; - Cache.infrastructureFull = 20; - Cache.infrastructureTarget = 0.75; - Cache.infrastructureWildernessSpread = 0.25; - Cache.infrastructureSpreadFloor = 0.5; - Cache.infrastructureStation = 10; - Cache.maxTradeUpkeep = 0.75; - for (Terrain terrain : Terrain.values()) Cache.tradeCarry.put(terrain, 0.5); - Cache.tradeCarry.put(Terrain.FARMLAND, 0.8); - Cache.tradeCarry.put(Terrain.PLAINS, 0.75); - Cache.tradeCarry.put(Terrain.BOG, 0.4); - Cache.tradeCarry.put(Terrain.MOUNTAIN, 0.3); - factions = mockStatic(FactionManager.class); - titles = mockStatic(TitleManager.class); - hubs = mockStatic(HubNetwork.class); - faction = mock(Faction.class); - when(faction.getId()).thenReturn("realm"); - guild = mock(Guild.class); - when(guild.getId()).thenReturn("guild"); - when(guild.getFaction()).thenReturn(faction); - when(guild.getTradeBreakdown()).thenReturn(new TradeBreakdown()); - when(guild.getModifier(GuildModifier.TRADE_CARRY)).thenReturn(1.0); - } - - @AfterEach - void restore() { - GuildModifierOverride.clear(); - hubs.close(); - titles.close(); - factions.close(); - Cache.tradeCarry.clear(); - Cache.tradeCarry.putAll(previousCarry); - Cache.provincesEnabled = previousEnabled; - Cache.infrastructureFull = previousFull; - Cache.infrastructureTarget = previousTarget; - Cache.infrastructureWildernessSpread = previousWilderness; - Cache.infrastructureSpreadFloor = previousFloor; - Cache.infrastructureStation = previousStation; - Cache.maxTradeUpkeep = previousMaxUpkeep; - } - - @Test - void anEmptySourceMapLeavesGuildCarryEqualToRawOnEveryTerrain() { - Map map = new HashMap<>(); - for (Terrain terrain : Terrain.values()) { - int id = terrain.ordinal() + 1; - map.put(id, new Province(id, terrain.name(), 0)); - } - ProvinceManager manager = manager(map); - manager.recalculate(); - - for (Province province : manager.getProvinces()) { - assertEquals(0, province.getInfrastructure()); - assertEquals(province.getTradeCarry(), province.getTradeCarry(guild)); - } - } - - @Test - void bothRecalculationPathsRebuildSourcesFromCurrentModifiers() { - Province first = new Province(1, "bog", 0); - Province second = new Province(2, "plains", 0); - first.addNeighbour(2); - second.addNeighbour(1); - titles.when(() -> TitleManager.getByProvince(1)).thenReturn(faction); - titles.when(() -> TitleManager.getByProvince(2)).thenReturn(faction); - capitalSource(10); - ProvinceManager manager = manager(Map.of(1, first, 2, second)); - - manager.recalculate(); - assertEquals(10, first.getInfrastructure()); - assertEquals(7.5, second.getInfrastructure(), 1e-9); - assertEquals(0.575, first.getTradeCarry(guild), 1e-9); - when(guild.getModifier(GuildModifier.INFRASTRUCTURE)).thenReturn(20.0); - manager.recalculateForSingleGuild(guild, false); - assertEquals(20, first.getInfrastructure()); - assertEquals(15, second.getInfrastructure(), 1e-9); - when(guild.getModifier(GuildModifier.INFRASTRUCTURE)).thenReturn(0.0); - manager.recalculate(); - assertEquals(0, first.getInfrastructure()); - assertEquals(first.getTradeCarry(), first.getTradeCarry(guild)); - } - - @Test - void snapshotsRebuildTheirOwnInfrastructureAndDoNotChangeTheLiveMap() { - Province capital = new Province(1, "bog", 0); - titles.when(() -> TitleManager.getByProvince(1)).thenReturn(faction); - capitalSource(10); - ProvinceManager live = manager(Map.of(1, capital)); - live.recalculate(); - EconomicPreview.Prepared prepared = EconomicPreview.prepare(live); - ProvinceManager snapshot = EconomicPreview.copyOf(prepared); - - assertNotSame(capital, snapshot.get(1)); - assertEquals(10, snapshot.get(1).getInfrastructure()); - GuildModifierOverride.use(guild, Map.of(GuildModifier.INFRASTRUCTURE, 20.0)); - snapshot.recalculate(); - GuildModifierOverride.clear(); - - assertEquals(20, snapshot.get(1).getInfrastructure()); - assertEquals(10, capital.getInfrastructure()); - assertEquals(10, EconomicPreview.copyOf(prepared).get(1).getInfrastructure()); - } - - @Test - void snapshotsReadInstallationsAtRecalculationTime() { - InstallationHandler handler = mock(InstallationHandler.class); - when(faction.getInstallationHandler()).thenReturn(handler); - factions.when(FactionManager::getCopy).thenReturn(List.of(faction)); - ProvinceManager live = manager(Map.of(1, new Province(1, "bog", 0))); - EconomicPreview.Prepared prepared = EconomicPreview.prepare(live); - Installation station = mock(Installation.class); - when(station.getKind()).thenReturn(InstallationKind.TRAIN_STATION); - when(station.getProvince()).thenReturn(1); - when(handler.getAll()).thenReturn(List.of(station)); - ProvinceManager snapshot = EconomicPreview.copyOf(prepared); - snapshot.recalculate(); - - assertEquals(10, snapshot.get(1).getInfrastructure()); - assertEquals(0, live.get(1).getInfrastructure()); - when(handler.getAll()).thenReturn(List.of()); - snapshot.recalculate(); - assertEquals(0, snapshot.get(1).getInfrastructure()); - } - - @Test - void singleGuildRecalculationRebuildsInstallationsEvenWithoutACapital() { - InstallationHandler handler = mock(InstallationHandler.class); - Installation station = mock(Installation.class); - when(station.getKind()).thenReturn(InstallationKind.TRAIN_STATION); - when(station.getProvince()).thenReturn(1); - when(handler.getAll()).thenReturn(List.of(station)); - when(faction.getInstallationHandler()).thenReturn(handler); - factions.when(FactionManager::getCopy).thenReturn(List.of(faction)); - ProvinceManager manager = manager(Map.of(1, new Province(1, "bog", 0))); - - manager.recalculateForSingleGuild(guild, false); - - assertEquals(10, manager.get(1).getInfrastructure()); - } - - @Test - void effectiveTerrainIsUsedByTradeProductionAndUpkeep() { - Province province = new Province(1, "bog", 0); - province.setInfrastructure(20); - ProvinceManager manager = manager(Map.of(1, province)); - province.calculateTrade(manager, guild, 10, 1); - - assertEquals(7.5, province.getRawGuildTrade(guild), 1e-9); - double factor = 7.5 / (7.5 + 2.5 / Math.sqrt(0.75)); - assertEquals(factor, province.getTradeFactor(guild), 1e-9); - province.calculateProduction(manager, guild, new ProvinceDataEntry(guild, 0, 10), 1); - assertEquals(10 * Math.sqrt(0.75) * factor, province.getGuildProduction(guild), 1e-9); - when(guild.getModifier(GuildModifier.TRADE_UPKEEP)).thenReturn(1.0); - province.setProsperity(100); - double expectedNet = Math.round(100 * (1 - factor) * 100) / 100.0; - assertEquals(expectedNet, manager.getIncome(guild, false), 1e-9); - assertEquals(0.4, province.getTradeCarry()); - assertEquals(0.4, Cache.getTradeCarry(Terrain.BOG)); - } - - @Test - void hubProductionSpreadUsesEffectiveTerrain() { - Province source = new Province(1, "plains", 0); - Province destination = new Province(2, "bog", 0); - source.addNeighbour(2); - destination.setInfrastructure(20); - destination.setData(guild.getId(), new ProvinceDataEntry(guild, 10, 0)); - ProvinceManager manager = manager(Map.of(1, source, 2, destination)); - source.seedProduction(manager, guild, 100); - - double factor = 10 / (10 + 2.5 / Math.sqrt(0.75)); - assertEquals(100 * Math.sqrt(0.75) * factor, destination.getGuildProduction(guild), 1e-9); - } - - @Test - void seaAndWaterCarryRemainRawEvenIfInfrastructureIsSet() { - for (Terrain terrain : List.of(Terrain.SEA, Terrain.WATER)) { - Province province = new Province(1, terrain.name(), 0); - province.setInfrastructure(20); - assertEquals(province.getTradeCarry(), province.getTradeCarry(guild)); - } - } - - private void capitalSource(double amount) { - when(guild.isBase()).thenReturn(true); - when(guild.hasCapital()).thenReturn(true); - when(guild.getCapital()).thenReturn(1); - when(guild.getModifier(GuildModifier.INFRASTRUCTURE)).thenReturn(amount); - factions.when(FactionManager::getAllGuilds).thenReturn(List.of(guild)); - } - - private static ProvinceManager manager(Map provinces) { - ProvinceManager manager = new ProvinceManager(); - manager.start(provinces); - return manager; - } -} diff --git a/src/test/java/net/tfminecraft/simplefactions/map/infra/TrackProvinceCacheTest.java b/src/test/java/net/tfminecraft/simplefactions/map/infra/TrackProvinceCacheTest.java index 71ed649d..bfbebd77 100644 --- a/src/test/java/net/tfminecraft/simplefactions/map/infra/TrackProvinceCacheTest.java +++ b/src/test/java/net/tfminecraft/simplefactions/map/infra/TrackProvinceCacheTest.java @@ -47,7 +47,7 @@ void vehicleFrameworkAbsentLogsOnlyOnce() { assertFalse(cache.refresh(() -> { cache.vehicleFrameworkUnavailable(message -> { - assertEquals("VehicleFramework is not enabled; railway track gives no infrastructure.", message); + assertEquals("VehicleFramework is not enabled; railway track is not read.", message); infoMessages.incrementAndGet(); }); return Set.of(); diff --git a/src/test/java/net/tfminecraft/simplefactions/map/provinces/ProvinceTradeCarryTest.java b/src/test/java/net/tfminecraft/simplefactions/map/provinces/ProvinceTradeCarryTest.java new file mode 100644 index 00000000..8edf0156 --- /dev/null +++ b/src/test/java/net/tfminecraft/simplefactions/map/provinces/ProvinceTradeCarryTest.java @@ -0,0 +1,105 @@ +package net.tfminecraft.simplefactions.map.provinces; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.when; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; + +import net.tfminecraft.simplefactions.Cache; +import net.tfminecraft.simplefactions.enums.GuildModifier; +import net.tfminecraft.simplefactions.enums.Terrain; +import net.tfminecraft.simplefactions.guild.Guild; +import net.tfminecraft.simplefactions.guild.income.TradeBreakdown; +import net.tfminecraft.simplefactions.managers.ProvinceManager; +import net.tfminecraft.simplefactions.managers.TitleManager; +import net.tfminecraft.simplefactions.objects.Faction; + +class ProvinceTradeCarryTest { + private final Map previousCarry = new HashMap<>(Cache.tradeCarry); + private final boolean previousEnabled = Cache.provincesEnabled; + private final double previousMaxUpkeep = Cache.maxTradeUpkeep; + private MockedStatic titles; + private Guild guild; + + @BeforeEach + void setUp() { + Cache.provincesEnabled = true; + Cache.maxTradeUpkeep = 0.75; + Cache.tradeCarry.put(Terrain.PLAINS, 0.75); + Cache.tradeCarry.put(Terrain.BOG, 0.4); + Cache.tradeCarry.put(Terrain.SEA, 0.6); + Cache.tradeCarry.put(Terrain.WATER, 0.75); + titles = mockStatic(TitleManager.class); + Faction faction = mock(Faction.class); + when(faction.getId()).thenReturn("realm"); + guild = mock(Guild.class); + when(guild.getId()).thenReturn("guild"); + when(guild.getFaction()).thenReturn(faction); + when(guild.getTradeBreakdown()).thenReturn(new TradeBreakdown()); + when(guild.getModifier(GuildModifier.TRADE_CARRY)).thenReturn(1.0); + } + + @AfterEach + void restore() { + titles.close(); + Cache.tradeCarry.clear(); + Cache.tradeCarry.putAll(previousCarry); + Cache.provincesEnabled = previousEnabled; + Cache.maxTradeUpkeep = previousMaxUpkeep; + } + + @Test + void tradeProductionAndUpkeepUseRawTerrain() { + Province province = new Province(1, "bog", 0); + ProvinceManager manager = manager(Map.of(1, province)); + province.calculateTrade(manager, guild, 10, 1); + + assertEquals(4.0, province.getRawGuildTrade(guild), 1e-9); + double factor = 4.0 / (4.0 + 2.5 / Math.sqrt(0.4)); + assertEquals(factor, province.getTradeFactor(guild), 1e-9); + province.calculateProduction(manager, guild, new ProvinceDataEntry(guild, 0, 10), 1); + assertEquals(10 * Math.sqrt(0.4) * factor, province.getGuildProduction(guild), 1e-9); + when(guild.getModifier(GuildModifier.TRADE_UPKEEP)).thenReturn(1.0); + province.setProsperity(100); + double expectedNet = Math.round(100 * (1 - factor) * 100) / 100.0; + assertEquals(expectedNet, manager.getIncome(guild, false), 1e-9); + assertEquals(0.4, province.getTradeCarry()); + assertEquals(0.4, Cache.getTradeCarry(Terrain.BOG)); + } + + @Test + void hubProductionSpreadUsesRawTerrain() { + Province source = new Province(1, "plains", 0); + Province destination = new Province(2, "bog", 0); + source.addNeighbour(2); + destination.setData(guild.getId(), new ProvinceDataEntry(guild, 10, 0)); + ProvinceManager manager = manager(Map.of(1, source, 2, destination)); + source.seedProduction(manager, guild, 100); + + double factor = 10 / (10 + 2.5 / Math.sqrt(0.4)); + assertEquals(100 * Math.sqrt(0.4) * factor, destination.getGuildProduction(guild), 1e-9); + } + + @Test + void seaAndWaterUseTheirConfiguredCarry() { + for (Terrain terrain : List.of(Terrain.SEA, Terrain.WATER)) { + Province province = new Province(1, terrain.name(), 0); + assertEquals(Cache.getTradeCarry(terrain), province.getTradeCarry()); + } + } + + private static ProvinceManager manager(Map provinces) { + ProvinceManager manager = new ProvinceManager(); + manager.start(provinces); + return manager; + } +}