Skip to content

Commit 080b4dc

Browse files
authored
Merge pull request #51 from BentoBoxWorld/develop
Release 1.18.0
2 parents 504ac7e + 6044c41 commit 080b4dc

48 files changed

Lines changed: 3519 additions & 17 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ release.properties
4646
dependency-reduced-pom.xml
4747
buildNumber.properties
4848

49+
# Test artifacts
50+
database/
51+
database_backup/
52+
4953
# Intellij
5054
*.iml
5155
*.java___jb_tmp___

pom.xml

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,14 @@
5858
<byte-buddy.version>1.17.5</byte-buddy.version>
5959
<!-- More visible way how to change dependency versions -->
6060
<paper.version>1.21.11-R0.1-SNAPSHOT</paper.version>
61-
<bentobox.version>2.7.1-SNAPSHOT</bentobox.version>
61+
<bentobox.version>3.17.0-SNAPSHOT</bentobox.version>
62+
<vault.version>1.7</vault.version>
6263
<!-- Revision variable removes warning about dynamic version -->
6364
<revision>${build.version}-SNAPSHOT</revision>
6465
<!-- Do not change unless you want different name for local builds. -->
6566
<build.number>-LOCAL</build.number>
6667
<!-- This allows to change between versions. -->
67-
<build.version>1.17.1</build.version>
68+
<build.version>1.18.0</build.version>
6869
<!-- Sonar Cloud -->
6970
<sonar.projectKey>BentoBoxWorld_addon-invSwitcher</sonar.projectKey>
7071
<sonar.organization>bentobox-world</sonar.organization>
@@ -114,14 +115,6 @@
114115
</profiles>
115116

116117
<repositories>
117-
<!-- jitpack first so MockBukkit snapshots resolve without hitting other repos -->
118-
<repository>
119-
<id>jitpack.io</id>
120-
<url>https://jitpack.io</url>
121-
<snapshots>
122-
<enabled>true</enabled>
123-
</snapshots>
124-
</repository>
125118
<repository>
126119
<id>spigot-repo</id>
127120
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots</url>
@@ -134,6 +127,11 @@
134127
<id>papermc</id>
135128
<url>https://repo.papermc.io/repository/maven-public/</url>
136129
</repository>
130+
<!-- Vault's own maven repo is unreliable, so we pull it from jitpack -->
131+
<repository>
132+
<id>jitpack.io</id>
133+
<url>https://jitpack.io</url>
134+
</repository>
137135
</repositories>
138136

139137
<dependencies>
@@ -146,9 +144,9 @@
146144
</dependency>
147145
<!-- MockBukkit -->
148146
<dependency>
149-
<groupId>com.github.MockBukkit</groupId>
150-
<artifactId>MockBukkit</artifactId>
151-
<version>v1.21-SNAPSHOT</version>
147+
<groupId>org.mockbukkit.mockbukkit</groupId>
148+
<artifactId>mockbukkit-v1.21</artifactId>
149+
<version>4.110.0</version>
152150
<scope>test</scope>
153151
<exclusions>
154152
<exclusion>
@@ -196,6 +194,14 @@
196194
<version>${bentobox.version}</version>
197195
<scope>provided</scope>
198196
</dependency>
197+
<!-- Vault: pulled from jitpack as their maven repo is unreliable -->
198+
<!-- See https://github.com/MilkBowl/VaultAPI/issues/69 -->
199+
<dependency>
200+
<groupId>com.github.MilkBowl</groupId>
201+
<artifactId>VaultAPI</artifactId>
202+
<version>${vault.version}</version>
203+
<scope>provided</scope>
204+
</dependency>
199205
</dependencies>
200206

201207
<build>

src/main/java/com/wasteofplastic/invswitcher/InvSwitcher.java

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,20 @@
88

99
import org.bukkit.Bukkit;
1010
import org.bukkit.World;
11+
import org.bukkit.plugin.RegisteredServiceProvider;
12+
import org.bukkit.plugin.ServicePriority;
1113

14+
import com.wasteofplastic.invswitcher.commands.admin.AdminMoneyCommand;
15+
import com.wasteofplastic.invswitcher.commands.user.BalanceCommand;
16+
import com.wasteofplastic.invswitcher.commands.user.PayCommand;
17+
import com.wasteofplastic.invswitcher.economy.InvEconomy;
1218
import com.wasteofplastic.invswitcher.listeners.PlayerListener;
1319

20+
import net.milkbowl.vault.economy.Economy;
1421
import world.bentobox.bentobox.api.addons.Addon;
1522
import world.bentobox.bentobox.api.configuration.Config;
1623
import world.bentobox.bentobox.database.DatabaseSetup.DatabaseType;
24+
import world.bentobox.bentobox.hooks.VaultHook;
1725

1826
/**
1927
* Inventory switcher for worlds. Switches advancements too.
@@ -31,6 +39,8 @@ public class InvSwitcher extends Addon {
3139

3240
private Set<World> worlds = new HashSet<>();
3341

42+
private InvEconomy economy;
43+
3444
@Override
3545
public void onLoad() {
3646
// Save default config.yml
@@ -74,6 +84,12 @@ public void allLoaded() {
7484
store = new Store(this);
7585
// Register the listeners
7686
registerListener(new PlayerListener(this));
87+
// Now that worlds are known, register the economy commands and placeholders. The economy
88+
// provider itself was registered earlier, in onEnable, so it beats shop plugins that cache
89+
// their Vault provider during their own startup.
90+
if (economy != null) {
91+
registerEconomyCommands();
92+
}
7793
}
7894

7995
@Override
@@ -82,19 +98,119 @@ public void onEnable() {
8298
if (this.getPlugin().getSettings().getDatabaseType().equals(DatabaseType.YAML)) {
8399
this.setState(State.DISABLED);
84100
this.logError("This addon is incompatible with YAML database. Please use another type, like JSON.");
101+
return;
102+
}
103+
// Register the Vault economy provider as early as possible (here in onEnable, not in
104+
// allLoaded) so it is in place before economy-consuming plugins (e.g. QuickShop) resolve
105+
// and cache their provider. The store, worlds and delegate are resolved lazily by
106+
// InvEconomy, so they do not need to exist yet.
107+
if (getSettings() != null && getSettings().isMoney()) {
108+
if (Bukkit.getPluginManager().getPlugin("Vault") == null) {
109+
logError("options.money is enabled but the Vault plugin is not installed - per-world money disabled.");
110+
} else {
111+
registerEconomyProvider();
112+
}
113+
}
114+
}
115+
116+
/**
117+
* Creates and registers InvSwitcher's per-world economy at the highest Vault priority so it
118+
* intercepts every economy call. Runs once. The provider is lazy - it resolves the store and
119+
* the delegate economy on first use - so this can run before those are ready.
120+
*/
121+
private void registerEconomyProvider() {
122+
if (economy != null) {
123+
return;
124+
}
125+
economy = new InvEconomy(this);
126+
Bukkit.getServicesManager().register(Economy.class, economy, getPlugin(), ServicePriority.Highest);
127+
128+
// BentoBox captured its VaultHook during early hook registration, before us, so it (and
129+
// addons that use it, e.g. Bank) still points at the previous economy. Re-run the hook so
130+
// it re-reads the now-highest provider (us). The VaultHook is a single shared instance held
131+
// by those addons, so refreshing it updates them too.
132+
refreshBentoBoxVaultHook();
133+
134+
// Dump the current economy provider chain (debug only) so it is clear we win the registration.
135+
if (getSettings().isEconomyDebug()) {
136+
logEconomyRegistrations();
85137
}
86138
}
87139

140+
/**
141+
* Registers the economy commands and placeholders against the game modes whose worlds
142+
* InvSwitcher manages. Called from allLoaded, once worlds are known.
143+
*/
144+
private void registerEconomyCommands() {
145+
PhManager phManager = new PhManager(this);
146+
getPlugin().getAddonsManager().getGameModeAddons().stream()
147+
.filter(gm -> worlds.contains(gm.getOverWorld()))
148+
.forEach(gm -> {
149+
gm.getPlayerCommand().ifPresent(pc -> {
150+
new BalanceCommand(this, pc);
151+
new PayCommand(this, pc);
152+
});
153+
gm.getAdminCommand().ifPresent(ac -> new AdminMoneyCommand(this, ac));
154+
if (!phManager.registerPlaceholders(gm)) {
155+
logWarning("Could not register economy placeholders - no PlaceholderManager available.");
156+
}
157+
log("Per-world economy hooking into " + gm.getDescription().getName());
158+
});
159+
}
160+
88161

89162
@Override
90163
public void onDisable() {
164+
// Unregister our economy so a reload does not stack providers
165+
if (economy != null) {
166+
Bukkit.getServicesManager().unregister(Economy.class, economy);
167+
economy = null;
168+
// Re-point BentoBox's VaultHook at whatever economy remains (e.g. EssentialsC)
169+
refreshBentoBoxVaultHook();
170+
}
91171
// save cache
92172
if (store != null) {
93173
getStore().saveOnShutdown();
94174
}
95175

96176
}
97177

178+
/**
179+
* Re-runs BentoBox's VaultHook so it re-reads the highest-priority economy currently
180+
* registered with the services manager. BentoBox addons such as Bank hold this same hook
181+
* instance, so they pick up the change without needing to re-hook themselves.
182+
*/
183+
private void refreshBentoBoxVaultHook() {
184+
getPlugin().getVault().ifPresent(VaultHook::hook);
185+
}
186+
187+
/**
188+
* Logs all registered Vault economy providers (highest priority first) and which one Vault
189+
* will hand out. Useful for confirming InvSwitcher won the registration and for spotting
190+
* consumers that cached a different provider before we registered.
191+
*/
192+
private void logEconomyRegistrations() {
193+
log("Vault economy providers now registered (used by new lookups):");
194+
for (RegisteredServiceProvider<Economy> r : Bukkit.getServicesManager().getRegistrations(Economy.class)) {
195+
log(" - " + r.getProvider().getName() + " (" + r.getProvider().getClass().getName()
196+
+ ") priority=" + r.getPriority() + " registeredBy=" + r.getPlugin().getName());
197+
}
198+
RegisteredServiceProvider<Economy> top = Bukkit.getServicesManager().getRegistration(Economy.class);
199+
if (top != null) {
200+
log("Vault.getRegistration(Economy) returns: " + top.getProvider().getName() + " ("
201+
+ top.getProvider().getClass().getName() + ")");
202+
}
203+
log("If a shop/economy plugin still uses the old balance, it cached its provider before now "
204+
+ "and must be loaded after BentoBox (or re-resolve on ServiceRegisterEvent).");
205+
}
206+
207+
/**
208+
* @return the per-world economy, or null if money is disabled or Vault is absent
209+
*/
210+
public InvEconomy getEconomy() {
211+
return economy;
212+
}
213+
98214

99215
/**
100216
* @return the store
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package com.wasteofplastic.invswitcher;
2+
3+
import com.wasteofplastic.invswitcher.economy.InvEconomy;
4+
5+
import world.bentobox.bentobox.BentoBox;
6+
import world.bentobox.bentobox.api.addons.GameModeAddon;
7+
import world.bentobox.bentobox.api.user.User;
8+
9+
/**
10+
* Registers PlaceholderAPI placeholders for a player's per-world balance.
11+
* @author tastybento
12+
*/
13+
public class PhManager {
14+
15+
private final BentoBox plugin;
16+
private final InvSwitcher addon;
17+
18+
public PhManager(InvSwitcher addon) {
19+
this.addon = addon;
20+
this.plugin = addon.getPlugin();
21+
}
22+
23+
/**
24+
* Register the balance placeholders for a game mode.
25+
* @param gm - game mode addon
26+
* @return true if registered, false if no placeholder manager is available
27+
*/
28+
public boolean registerPlaceholders(GameModeAddon gm) {
29+
if (plugin.getPlaceholdersManager() == null) {
30+
return false;
31+
}
32+
String prefix = gm.getDescription().getName().toLowerCase() + "_invswitcher_";
33+
// Balance is scoped to this game mode's world, so the placeholder is stable regardless of
34+
// where the player currently is (e.g. bskyblock_invswitcher_balance is the BSkyBlock balance).
35+
String worldName = gm.getOverWorld().getName();
36+
// Raw balance number
37+
plugin.getPlaceholdersManager().registerPlaceholder(addon, prefix + "balance",
38+
user -> balance(user, worldName, false));
39+
// Formatted balance (currency name + decimals)
40+
plugin.getPlaceholdersManager().registerPlaceholder(addon, prefix + "balance_formatted",
41+
user -> balance(user, worldName, true));
42+
return true;
43+
}
44+
45+
private String balance(User user, String worldName, boolean formatted) {
46+
InvEconomy eco = addon.getEconomy();
47+
if (eco == null || user == null || !user.isPlayer()) {
48+
return "";
49+
}
50+
double bal = eco.getBalance(user.getPlayer(), worldName);
51+
return formatted ? eco.format(bal) : String.valueOf(bal);
52+
}
53+
}

0 commit comments

Comments
 (0)