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
2 changes: 2 additions & 0 deletions src/main/java/net/tfminecraft/simplefactions/Cache.java
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ public static boolean requireProvinces(org.bukkit.command.CommandSender sender)
public static boolean supplyHubAutoAccept = false;
/** Share of a hop kept at an end where the guild has no active hub. */
public static double supplyHubNoHubStrength = 0.5;
/** 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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
/**
* Trade along the shared graph. A hop is one edge, in one direction, and it repeats until
* nothing larger arrives. Production uses {@link #links}, which keeps only pairs hubbed at both ends.
* Sea and rail then leave a share in the provinces along each edge. That does not start another hop.
*/
public final class Highway {
/** A trade node where the guild has an active hub. Ids are compared ignoring case. */
Expand Down Expand Up @@ -59,6 +60,15 @@ public static double noHubStrength() {
return Math.max(0, Math.min(1, value));
}

/** Clamped to 0..1. Missing or non-finite config uses the default half. */
public static double corridorShare() {
double value = Cache.supplyHubCorridorShare;
if (!Double.isFinite(value)) {
return 0.5;
}
return Math.max(0, Math.min(1, value));
}

/**
* Seeds trade from each node that can send, highest raw trade first, until a pass moves nothing.
* {@code hubbed} may be empty: both ends then use {@link #noHubStrength()}.
Expand Down Expand Up @@ -103,6 +113,81 @@ public static void deliver(
}
}

/**
* Seeds sea and rail provinces along each edge, in both directions. Call this only after
* {@link #deliver} has settled. Each sending node's raw trade is read before any seed, so one
* deposit's spread cannot raise the next deposit's source. Air leaves nothing. The receiving
* end's hub does not change the amount.
*/
public static void deposit(
ProvinceManager provinces, Guild guild, TradeGraph graph, Set<HubSite> hubbed, double hubTradeBonus) {
if (provinces == null || guild == null || guild.getId() == null || graph == null || graph.edges().isEmpty()) {
return;
}
double corridor = corridorShare();
if (corridor <= 0) {
return;
}
Set<Node> hubNodes = hubNodes(graph, hubbed);
double strength = noHubStrength();
double bonus = Math.max(0, hubTradeBonus);
Map<Node, Double> rawAt = new HashMap<>();
for (Node node : graph.nodes()) {
rawAt.put(node, raw(provinces, guild, node));
}
for (Edge edge : graph.edges()) {
if (edge.mode() == Mode.AIR || edge.provinces().isEmpty()) {
continue;
}
depositDirection(provinces, guild, edge, edge.first(), hubNodes, strength, bonus, corridor, rawAt);
depositDirection(provinces, guild, edge, edge.second(), hubNodes, strength, bonus, corridor, rawAt);
}
}

private static void depositDirection(
ProvinceManager provinces, Guild guild, Edge edge, Node from, Set<Node> hubNodes,
double strength, double bonus, double corridor, Map<Node, Double> rawAt) {
List<Integer> along = edge.provincesFrom(from);
int count = along.size();
if (count == 0) {
return;
}
double rawFrom = rawAt.getOrDefault(from, 0.0);
if (rawFrom < 0.5) {
return;
}
boolean fromHub = hubNodes.contains(from);
double end = fromHub ? 1 : strength;
Rates rates = HubTransport.rates(edge.mode());
double share = tradeShare(rates.trade(), fromHub ? bonus : 0);
// Kept-per-1000 is at most 0.95, so distance only shrinks the deposit.
if (rawFrom * end * share * corridor < 0.5) {
return;
}
double length = Math.max(0, edge.length());
for (int index = 0; index < count; index++) {
int provinceId = along.get(index);
if (!provinces.contains(provinceId)) {
continue;
}
double distance = length * (index + 1.0) / (count + 1.0);
double amount = rawFrom * end * HubTransport.delivered(share, rates.keptPer1000(), distance) * corridor;
provinces.get(provinceId).seedTrade(provinces, guild, amount);
}
}

/** The mode's trade share, capped the same way a hop caps {@code HUB_TRADE}. */
private static double tradeShare(double trade, double bonus) {
if (!Double.isFinite(trade) || trade <= 0) {
return 0;
}
double share = Math.min(HubTransport.MAX_SHARE, trade);
if (bonus > 0) {
share = Math.min(HubTransport.MAX_SHARE, share * (1.0 + bonus));
}
return share;
}

/**
* Both directions of each pair the guild has hubbed at both ends. The mode is the one with the
* higher trade factor; rail wins a tie. Safe on any thread.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ public static void loadConfig(FileConfiguration config) {
Cache.supplyHubAutoAccept = config != null && config.getBoolean("supply-hubs.auto-accept", false);
double strength = config == null ? 0.5 : config.getDouble("supply-hubs.no-hub-strength", 0.5);
Cache.supplyHubNoHubStrength = Double.isFinite(strength) ? Math.max(0, Math.min(1, strength)) : 0.5;
double corridor = config == null ? 0.5 : config.getDouble("supply-hubs.corridor-share", 0.5);
Cache.supplyHubCorridorShare = Double.isFinite(corridor) ? Math.max(0, Math.min(1, corridor)) : 0.5;
}

public static int limit(Guild guild) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,12 +324,14 @@ this, guild, graphFor(), hubbedFor(guild),
}
}

/** Sea and rail corridor deposits. Runs only after the highway has settled. */
/** Sea and rail corridor deposits. Runs only after the highway has settled, and does not run it again. */
private void depositCorridors(Guild guild) {
// Filled in when corridor deposits are added. The highway is not run again after this.
if (guild == null) {
return;
}
Highway.deposit(
this, guild, graphFor(), hubbedFor(guild),
GuildModifierOverride.resolve(guild, GuildModifier.HUB_TRADE));
}

private void carryProductionThroughHubs(Guild guild) {
Expand Down
3 changes: 3 additions & 0 deletions src/main/resources/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ supply-hubs:
# Trade without your hub at a stop is carried at this strength. Both ends
# without a hub multiply it twice. 1 is full strength.
no-hub-strength: 0.5
# Sea and rail leave this share of the delivery in the provinces along the way.
# Air leaves nothing. 1 leaves the full delivery.
corridor-share: 0.5
# A stop delivers a share of the guild's trade there to the next stop.
# trade / production: share delivered before distance loss (capped at 0.95)
# kept-per-1000-blocks: share that survives each 1000 blocks
Expand Down
Loading
Loading