Skip to content

feat: Add ExcellentShop v5 shop integration#252

Open
jayesh-kambli wants to merge 8 commits into
NighterDevelopment:mainfrom
jayesh-kambli:feature/excellentshop-integration
Open

feat: Add ExcellentShop v5 shop integration#252
jayesh-kambli wants to merge 8 commits into
NighterDevelopment:mainfrom
jayesh-kambli:feature/excellentshop-integration

Conversation

@jayesh-kambli
Copy link
Copy Markdown

Summary

Adds ExcellentShopProvider so SmartSpawner can read sell prices directly from ExcellentShop v5 virtual shops.

Changes

New file: ExcellentShopProvider.java

  • Implements ShopProvider for ExcellentShop v5 (su.nightexpress.excellentshop)
  • Scans all VirtualShop products on ServerLoadEvent (after ExcellentShop async data load completes) and caches the best sell price per Material
  • Only indexes items that are isSellable() and ContentType.ITEM
  • Keeps the highest sell price when the same material appears in multiple shops
  • Cache uses ConcurrentHashMap + AtomicBoolean for Folia thread safety
  • invalidateCache() available for reload scenarios

ShopIntegrationManager.java

  • Registered in auto-detect flow
  • Registered for explicit config: preferred_plugin: ExcellentShop

paper-plugin.yml

  • Added ExcellentShop: load: BEFORE to dependencies to guarantee correct load order (SmartSpawner is a Paper plugin, ExcellentShop is a Bukkit plugin so softdepend in plugin.yml has no effect between the two)

plugin.yml

  • Added ExcellentShop to softdepend for Bukkit-level awareness

build.gradle.kts

  • Added mavenLocal() to repositories for locally built ExcellentShop API
  • Added content filter to nightexpress repo (only su.nightexpress.*) to prevent timeout cascades when resolving unrelated dependencies

Testing

Tested on Paper 1.21.11 and Canvas 1.21.11 (Folia fork) with ExcellentShop v5.1.1 and NightCore 2.15.3.

On startup:

[SmartSpawner] [ExcellentShop] Integration ready. Price cache will build after server finishes loading.
[SmartSpawner] Auto-detected & successfully hook into shop plugin: ExcellentShop
[SmartSpawner] [ExcellentShop] Price cache built: 635 materials indexed.

- Add ExcellentShopProvider: scans VirtualShop products, caches best
  sell price per Material (lazy, invalidatable), returns 0 for non-item
  or non-sellable products
- Wire into ShopIntegrationManager auto-detect and specific config cases
- Add su.nightexpress.excellentshop api+Core as compileOnly dependencies
- Add mavenLocal() to repository list for locally built ExcellentShop
- Add content filter to nightexpress repo (su.nightexpress.* only) to
  prevent timeouts when resolving unrelated dependencies
- Bump targetJavaVersion: 25 kept as-is (requires JDK 25 to build)
…heck

- Add ExcellentShop to plugin.yml softdepend so Bukkit loads it before
  SmartSpawner, ensuring ShopAPI is initialized when isAvailable() runs
- Remove ShopAPI.isInitialized() guard from isAvailable() since plugin
  being enabled is sufficient — the API is always ready at that point
- Cache now builds on ServerLoadEvent instead of lazily on first call,
  ensuring ExcellentShop's async data load is complete before reading prices
- AtomicBoolean for cacheBuilt prevents double-build race condition on Folia
- ConcurrentHashMap for thread-safe reads from multiple region threads
- Fix sellPrice filter: was dropping sellPrice=0 (valid price), now only
  drops sellPrice<0 (-1 = disabled)
- Allow cache retry if build fails (cacheBuilt reset on exception)
- Register as Listener inside isAvailable() for ServerLoadEvent
- Detailed logging at each failure point
softdepend in plugin.yml has no effect for Paper plugins - load order
between Paper plugins and Bukkit plugins is controlled by paper-plugin.yml.
ExcellentShop (Bukkit plugin) must load BEFORE SmartSpawner (Paper plugin)
so the API is initialized when isAvailable() runs.
Shows all sellable items across all spawners grouped by spawner type,
with per-item price source breakdown:
- [Shop]         price sourced from ExcellentShop (green)
- [Custom]       price from item_prices.yml (yellow)
- [Fallback]     secondary source used due to priority mode (yellow)
- [Not Configured] no price found in any source (red)

Fully respects price_source_mode (SHOP_PRIORITY, CUSTOM_PRIORITY,
SHOP_ONLY, CUSTOM_ONLY). Summary at bottom shows counts per category
with a warning if any items are unconfigured.

Exposed getShopPriceFor(), getCustomPriceFor(), getPriceSourceMode()
on ItemPriceManager for analysis use.
Permission: smartspawner.command.priceanalysis (default: op)
/ss priceanalysis           — all spawners (existing behavior)
/ss priceanalysis <tab>     — autocompletes only entity types that have
                              active spawners loaded on the server
/ss priceanalysis pig       — individual lookup for that spawner type

Tab completion is dynamic: queries actual loaded spawners so it only
suggests types that exist, not the full EntityType enum.
SHOP_ONLY  -> only mention shop plugin
CUSTOM_ONLY -> only mention item_prices.yml
SHOP_PRIORITY / CUSTOM_PRIORITY -> mention both with correct preference order
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant