88
99import org .bukkit .Bukkit ;
1010import 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 ;
1218import com .wasteofplastic .invswitcher .listeners .PlayerListener ;
1319
20+ import net .milkbowl .vault .economy .Economy ;
1421import world .bentobox .bentobox .api .addons .Addon ;
1522import world .bentobox .bentobox .api .configuration .Config ;
1623import 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
0 commit comments