Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,26 @@ public static double infrastructureWorth(String realmId) {
return 0;
}

/** False before the first daily pass, so a menu can avoid showing a missing figure as +0. */
public static boolean hasInfrastructureWorth(Faction realm) {
return realm != null && hasInfrastructureWorth(realm.getId());
}

public static boolean hasInfrastructureWorth(String realmId) {
if (realmId == null) {
return false;
}
if (headlines.containsKey(realmId)) {
return true;
}
for (String key : headlines.keySet()) {
if (realmId.equalsIgnoreCase(key)) {
return true;
}
}
return false;
}

public static Terms applyTerms(Destination destination, int ratePercent, long feeCents) {
if (destination == null) {
return new Terms(0, 0, 0, 0);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
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<String> installationPreview(HubEstimates.InstallationPreview preview) {
if (preview == null) {
return List.of(calculating());
}
List<String> 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);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
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;
Expand All @@ -9,7 +11,9 @@
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;

/**
Expand Down Expand Up @@ -65,6 +69,52 @@ public static double estimate(
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<Guild> guildsNow() {
List<Guild> guilds = new ArrayList<>();
for (Guild guild : FactionManager.getAllGuilds()) {
if (guild != null) {
guilds.add(guild);
}
}
return List.copyOf(guilds);
}

public static List<Faction> factionsNow() {
List<Faction> 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<GuildModifier, Double> current,
Map<GuildModifier, Double> hypothetical,
List<Guild> guilds,
List<Faction> 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<GuildModifier, Double> modifiers(Guild guild) {
EnumMap<GuildModifier, Double> amounts = new EnumMap<>(GuildModifier.class);
for (GuildModifier modifier : GuildModifier.values()) {
Expand Down Expand Up @@ -105,6 +155,45 @@ private static ProvinceManager copy(ProvinceManager source) {
return snapshot;
}

private static double realmIncome(
Prepared prepared,
Guild realmGuild,
Map<GuildModifier, Double> amounts,
List<Guild> guilds,
List<Faction> factions) {
ProvinceManager snapshot = copy(prepared.snapshot);
GuildModifierOverride.use(realmGuild, amounts);
try {
snapshot.recalculateQuiet(guilds, factions);
double sum = 0;
Faction realm = realmGuild.getFaction();
List<Guild> 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();
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

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<GuildModifier, Double> amounts) {
GuildModifierOverride.use(guild, amounts);
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
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;
Expand Down Expand Up @@ -623,15 +624,15 @@ private boolean dispatchCommand(CommandSender sender, Command cmd, String label,
return true;
}
String name = String.join(" ", Arrays.copyOfRange(args, 2, args.length));
ConstructResult result = f.getInstallationHandler().construct(
if (InstallationBuildConfirm.open(
p,
f,
kind,
name,
province,
p.getLocation().getBlockX(),
p.getLocation().getBlockZ());
p.sendMessage(result.getMessage());
if(result.isSuccess()) {
p.playSound(p, Sound.BLOCK_ANVIL_USE, 1f, 1f);
p.getLocation().getBlockZ())) {
p.playSound(p, Sound.BLOCK_NOTE_BLOCK_BIT, 1f, 1f);
}
return true;
} else if(cmd.getName().equalsIgnoreCase(cmd1) && args[0].equalsIgnoreCase("deconstruct")) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
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;
Expand Down Expand Up @@ -1001,6 +1002,8 @@ 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());
}

Expand Down Expand Up @@ -1477,6 +1480,17 @@ 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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import org.bukkit.Bukkit;

Expand Down Expand Up @@ -37,6 +39,9 @@

public class ProvinceManager {
private Map<Integer, Province> provinces = new HashMap<>();
/** Set only on a preview copy, so a background flood does not walk the live faction list. */
private List<Guild> previewGuilds;
private List<Faction> previewFactions;
private Map<String, List<Link>> hubLinksOverride;
private boolean infrastructureSuppressed;
private Map<Integer, Double> extraInfrastructure;
Expand Down Expand Up @@ -140,6 +145,38 @@ public void recalculate() {
for(Guild guild : FactionManager.getAllGuilds()) getIncome(guild);
}

/**
* Same flood as {@link #recalculate()} without writing guild trade breakdowns.
* {@code guilds} and {@code factions} are copies taken on the server thread.
*/
public void recalculateQuiet(List<Guild> guilds, List<Faction> factions) {
if (!Cache.provincesEnabled) {
return;
}
previewGuilds = guilds == null ? List.of() : List.copyOf(guilds);
previewFactions = factions == null ? List.of() : List.copyOf(factions);
HubNetwork.refreshIfLive(this);
recalculateInfrastructure();
dropExcept(previewGuilds);
for (Guild guild : previewGuilds) {
if (guild != null && guild.hasCapital()) {
recalculateGuild(guild);
}
}
for (Guild guild : previewGuilds) {
if (guild != null && guild.hasCapital()) {
recalculateProduction(guild);
}
}
recalculateProsperity();
}

/** Drops the copies {@link #recalculateQuiet} kept for the income read that follows. */
public void clearPreviewLists() {
previewGuilds = null;
previewFactions = null;
}

public void recalculateForSingleGuild(Guild g, boolean save) {
if (!Cache.provincesEnabled) {
return;
Expand Down Expand Up @@ -167,13 +204,16 @@ private void recalculateInfrastructure() {
}
Map<Integer, InfrastructureSpread.Node> graph = new HashMap<>();
for (Province province : provinces.values()) {
Faction realm = InfrastructureAccess.topRealm(province.getOwner());
Faction realm = InfrastructureAccess.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<Integer, Double> sources = InfrastructureSources.collect(
provinces, FactionManager.getAllGuilds(), FactionManager.getCopy(),
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<Integer, Double> extra : extraInfrastructure.entrySet()) {
Expand Down Expand Up @@ -296,7 +336,9 @@ public double getIncome(Guild guild, boolean save) {
if(provinceIncome == 0) continue;
//if(provinceIncome > guildTrade) provinceIncome = guildTrade;
upkeep += provinceIncome*TradeUpkeep.rate(province.getTradeFactor(guild), upkeepFactor);
Faction owner = TitleManager.getByProvince(province.getId());
Faction owner = previewFactions != null
? ownerOf(province.getId())
: TitleManager.getByProvince(province.getId());
if(owner != null) {
if(save) guild.getTradeBreakdown().registerIncome(owner, provinceIncome);
if(!RelationManager.sameRealm(owner, guild.getFaction())){
Expand Down Expand Up @@ -369,6 +411,35 @@ public double previewDowngradeIncomeExact(Guild guild, Branch branch) {
}

//Simulation
private void dropExcept(List<Guild> present) {
Set<String> ids = new HashSet<>();
for (Guild guild : present) {
if (guild != null && guild.getId() != null) {
ids.add(guild.getId().toLowerCase(Locale.ROOT));
}
}
for (Province province : provinces.values()) {
List<String> remove = new ArrayList<>();
for (String id : province.getAllData().keySet()) {
if (id == null || !ids.contains(id.toLowerCase(Locale.ROOT))) {
remove.add(id);
}
}
for (String id : remove) {
province.clearGuildData(id);
}
}
}

private Faction ownerOf(int provinceId) {
for (Faction faction : previewFactions) {
if (faction != null && faction.hasProvince(provinceId)) {
return faction;
}
}
return null;
}

public void copyAllDataFrom(ProvinceManager source) {
for (Province src : source.provinces.values()) {
Province dst = provinces.get(src.getId());
Expand Down
Loading
Loading