diff --git a/src/main/java/com/github/mkram17/bazaarutils/commands/DeveloperCommands.java b/src/main/java/com/github/mkram17/bazaarutils/commands/DeveloperCommands.java index 39270757..c446c2b7 100644 --- a/src/main/java/com/github/mkram17/bazaarutils/commands/DeveloperCommands.java +++ b/src/main/java/com/github/mkram17/bazaarutils/commands/DeveloperCommands.java @@ -2,12 +2,12 @@ import com.github.mkram17.bazaarutils.config.features.DeveloperConfig; import com.github.mkram17.bazaarutils.config.util.ConfigUtil; -import com.github.mkram17.bazaarutils.data.UserOrdersStorage; +import com.github.mkram17.bazaarutils.utils.storage.UserOrdersStorage; import com.github.mkram17.bazaarutils.features.notification.OutbidOrderHandler; import com.github.mkram17.bazaarutils.misc.NotificationType; import com.github.mkram17.bazaarutils.utils.PlayerActionUtil; import com.github.mkram17.bazaarutils.utils.annotations.modules.Module; -import com.github.mkram17.bazaarutils.utils.bazaar.data.BazaarDataManager; +import com.github.mkram17.bazaarutils.utils.bazaar.data.BazaarDataUtil; import com.github.mkram17.bazaarutils.utils.bazaar.market.order.Order; import com.github.mkram17.bazaarutils.utils.bazaar.market.order.TransactionType; import com.mojang.brigadier.arguments.IntegerArgumentType; @@ -152,7 +152,7 @@ private int convertNameToId(CommandContext context) { if (!isEnabled()) return 0; String name = StringArgumentType.getString(context, "item name").replaceAll("_", " "); - BazaarDataManager.findProductIdOptional(name).ifPresentOrElse( + BazaarDataUtil.findProductIdOptional(name).ifPresentOrElse( id -> PlayerActionUtil.notifyAll(name + ": " + id), () -> PlayerActionUtil.notifyAll("Could not find product ID for " + name) ); diff --git a/src/main/java/com/github/mkram17/bazaarutils/events/BazaarDataUpdateEvent.java b/src/main/java/com/github/mkram17/bazaarutils/events/BazaarDataUpdateEvent.java index f407a555..483487c1 100644 --- a/src/main/java/com/github/mkram17/bazaarutils/events/BazaarDataUpdateEvent.java +++ b/src/main/java/com/github/mkram17/bazaarutils/events/BazaarDataUpdateEvent.java @@ -1,40 +1,28 @@ package com.github.mkram17.bazaarutils.events; -import lombok.AllArgsConstructor; +import com.github.mkram17.bazaarutils.utils.bazaar.data.wrappers.CustomBazaarReply; import lombok.Getter; import meteordevelopment.orbit.ICancellable; -import net.hypixel.api.reply.skyblock.SkyBlockBazaarReply; /** * Event fired when bazaar data is updated from the Hypixel API. *

* This event is triggered whenever fresh bazaar market data is retrieved from the Hypixel API. - * It provides access to the complete bazaar reply containing all current market prices, volumes, - * and other bazaar statistics. + * It provides access to the converted custom bazaar reply containing all current market prices, + * volumes, and other bazaar statistics. *

- * - *

Usage Example:

- *
- * {@code
- * @EventHandler
- * public void onBazaarDataUpdate(BazaarDataUpdateEvent event) {
- *     SkyBlockBazaarReply reply = event.getBazaarReply();
- *     // Update local cache with new market data
- *     updatePriceCache(reply);
- * }
- * }
- * 
- * - * @see SkyBlockBazaarReply */ -@AllArgsConstructor public class BazaarDataUpdateEvent implements ICancellable { /** - * The bazaar data reply from the Hypixel API containing current market information. + * The converted bazaar data reply containing current market information. */ @Getter - private SkyBlockBazaarReply bazaarReply; + private final CustomBazaarReply bazaarReply; + + public BazaarDataUpdateEvent(CustomBazaarReply bazaarReply) { + this.bazaarReply = bazaarReply; + } @Override public void setCancelled(boolean cancelled) { diff --git a/src/main/java/com/github/mkram17/bazaarutils/events/handler/BazaarChatEventHandler.java b/src/main/java/com/github/mkram17/bazaarutils/events/handler/BazaarChatEventHandler.java index da22f135..57b9e580 100644 --- a/src/main/java/com/github/mkram17/bazaarutils/events/handler/BazaarChatEventHandler.java +++ b/src/main/java/com/github/mkram17/bazaarutils/events/handler/BazaarChatEventHandler.java @@ -2,7 +2,7 @@ import com.github.mkram17.bazaarutils.config.BUConfig; import com.github.mkram17.bazaarutils.config.features.notification.NotificationsConfig; -import com.github.mkram17.bazaarutils.data.UserOrdersStorage; +import com.github.mkram17.bazaarutils.utils.storage.UserOrdersStorage; import com.github.mkram17.bazaarutils.events.BazaarChatEvent; import com.github.mkram17.bazaarutils.features.gui.overlays.BazaarLimitsVisualizer; import com.github.mkram17.bazaarutils.misc.NotificationType; diff --git a/src/main/java/com/github/mkram17/bazaarutils/events/handler/ChatHandler.java b/src/main/java/com/github/mkram17/bazaarutils/events/handler/ChatHandler.java index 46885892..407d2e0f 100644 --- a/src/main/java/com/github/mkram17/bazaarutils/events/handler/ChatHandler.java +++ b/src/main/java/com/github/mkram17/bazaarutils/events/handler/ChatHandler.java @@ -1,7 +1,7 @@ package com.github.mkram17.bazaarutils.events.handler; import com.github.mkram17.bazaarutils.config.BUConfig; -import com.github.mkram17.bazaarutils.data.UserOrdersStorage; +import com.github.mkram17.bazaarutils.utils.storage.UserOrdersStorage; import com.github.mkram17.bazaarutils.events.BazaarChatEvent; import com.github.mkram17.bazaarutils.misc.NotificationType; import com.github.mkram17.bazaarutils.utils.annotations.autoregistration.RunOnInit; diff --git a/src/main/java/com/github/mkram17/bazaarutils/features/gui/buttons/bookmarks/BookmarkUtil.java b/src/main/java/com/github/mkram17/bazaarutils/features/gui/buttons/bookmarks/BookmarkUtil.java index 96dc34a4..26150718 100644 --- a/src/main/java/com/github/mkram17/bazaarutils/features/gui/buttons/bookmarks/BookmarkUtil.java +++ b/src/main/java/com/github/mkram17/bazaarutils/features/gui/buttons/bookmarks/BookmarkUtil.java @@ -1,7 +1,7 @@ package com.github.mkram17.bazaarutils.features.gui.buttons.bookmarks; import com.github.mkram17.bazaarutils.BazaarUtils; -import com.github.mkram17.bazaarutils.data.BookmarksStorage; +import com.github.mkram17.bazaarutils.utils.storage.BookmarksStorage; import lombok.Getter; import net.minecraft.client.gui.screen.ButtonTextures; import net.minecraft.util.Identifier; diff --git a/src/main/java/com/github/mkram17/bazaarutils/features/gui/overlays/BazaarLimitsVisualizer.java b/src/main/java/com/github/mkram17/bazaarutils/features/gui/overlays/BazaarLimitsVisualizer.java index 45c9c1ec..b8349456 100644 --- a/src/main/java/com/github/mkram17/bazaarutils/features/gui/overlays/BazaarLimitsVisualizer.java +++ b/src/main/java/com/github/mkram17/bazaarutils/features/gui/overlays/BazaarLimitsVisualizer.java @@ -6,7 +6,7 @@ import java.util.List; import com.github.mkram17.bazaarutils.config.features.gui.OverlaysConfig; -import com.github.mkram17.bazaarutils.data.BazaarLimitsStorage; +import com.github.mkram17.bazaarutils.utils.storage.BazaarLimitsStorage; import com.github.mkram17.bazaarutils.events.listener.BUListener; import com.github.mkram17.bazaarutils.generated.BazaarUtilsModules; import com.github.mkram17.bazaarutils.misc.BUCompatibilityHelper; diff --git a/src/main/java/com/github/mkram17/bazaarutils/features/gui/overlays/PriceCharts.java b/src/main/java/com/github/mkram17/bazaarutils/features/gui/overlays/PriceCharts.java index f9a34350..a6dc59d7 100644 --- a/src/main/java/com/github/mkram17/bazaarutils/features/gui/overlays/PriceCharts.java +++ b/src/main/java/com/github/mkram17/bazaarutils/features/gui/overlays/PriceCharts.java @@ -2,9 +2,9 @@ import com.github.mkram17.bazaarutils.config.features.gui.OverlaysConfig; import com.github.mkram17.bazaarutils.utils.annotations.modules.Module; -import com.github.mkram17.bazaarutils.utils.bazaar.data.BazaarDataManager; import com.github.mkram17.bazaarutils.events.SlotClickEvent; import com.github.mkram17.bazaarutils.events.listener.BUListener; +import com.github.mkram17.bazaarutils.utils.bazaar.data.BazaarDataUtil; import com.github.mkram17.bazaarutils.utils.config.BUToggleableFeature; import com.github.mkram17.bazaarutils.utils.bazaar.gui.BazaarScreens; import com.github.mkram17.bazaarutils.utils.bazaar.market.order.OrderInfo; @@ -78,7 +78,7 @@ private void onClick(SlotClickEvent e){ return; } - String productID = BazaarDataManager.findProductIdOptional(itemName).get(); // All cached items are safe + String productID = BazaarDataUtil.findProductIdOptional(itemName).get(); // All cached items are safe String link = "https://skyblock.finance/items/" + productID; MinecraftClient.getInstance().setScreen(new ConfirmLinkScreen(confirmed -> { diff --git a/src/main/java/com/github/mkram17/bazaarutils/features/notification/OutbidOrderHandler.java b/src/main/java/com/github/mkram17/bazaarutils/features/notification/OutbidOrderHandler.java index 2cb95773..857adeb7 100644 --- a/src/main/java/com/github/mkram17/bazaarutils/features/notification/OutbidOrderHandler.java +++ b/src/main/java/com/github/mkram17/bazaarutils/features/notification/OutbidOrderHandler.java @@ -1,7 +1,7 @@ package com.github.mkram17.bazaarutils.features.notification; import com.github.mkram17.bazaarutils.config.features.notification.NotificationsConfig; -import com.github.mkram17.bazaarutils.data.UserOrdersStorage; +import com.github.mkram17.bazaarutils.utils.storage.UserOrdersStorage; import com.github.mkram17.bazaarutils.utils.annotations.modules.Module; import com.github.mkram17.bazaarutils.utils.config.BUToggleableFeature; import com.github.mkram17.bazaarutils.utils.bazaar.market.order.Order; diff --git a/src/main/java/com/github/mkram17/bazaarutils/data/APIUtils.java b/src/main/java/com/github/mkram17/bazaarutils/utils/APIUtil.java similarity index 91% rename from src/main/java/com/github/mkram17/bazaarutils/data/APIUtils.java rename to src/main/java/com/github/mkram17/bazaarutils/utils/APIUtil.java index dda16ddd..0b8a02f4 100644 --- a/src/main/java/com/github/mkram17/bazaarutils/data/APIUtils.java +++ b/src/main/java/com/github/mkram17/bazaarutils/utils/APIUtil.java @@ -1,11 +1,11 @@ -package com.github.mkram17.bazaarutils.data; +package com.github.mkram17.bazaarutils.utils; import net.hypixel.api.HypixelAPI; import net.hypixel.api.apache.ApacheHttpClient; import java.util.UUID; -public class APIUtils { +public class APIUtil { public static String getApiKey() { String apiKey = System.getenv("HYPIXEL_API_KEY"); diff --git a/src/main/java/com/github/mkram17/bazaarutils/utils/ResourceManager.java b/src/main/java/com/github/mkram17/bazaarutils/utils/ResourceManager.java index 0668ce70..2c79021c 100644 --- a/src/main/java/com/github/mkram17/bazaarutils/utils/ResourceManager.java +++ b/src/main/java/com/github/mkram17/bazaarutils/utils/ResourceManager.java @@ -4,10 +4,13 @@ import com.github.mkram17.bazaarutils.config.BUConfig; import com.github.mkram17.bazaarutils.config.hidden.MetadataConfig; import com.github.mkram17.bazaarutils.config.util.ConfigUtil; +import com.github.mkram17.bazaarutils.misc.NotificationType; import com.github.mkram17.bazaarutils.utils.bazaar.data.BazaarDataManager; import com.github.mkram17.bazaarutils.utils.annotations.autoregistration.RunOnInit; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import lombok.Getter; +import lombok.Setter; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.MinecraftClient; @@ -22,8 +25,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; -import java.util.Optional; -import java.util.Scanner; +import java.util.*; import java.util.concurrent.CompletableFuture; //TODO move config to config/bazaarutils directory and rename to "config". See how REI does this. @@ -33,6 +35,11 @@ public class ResourceManager { private static final Path LOCAL_RESOURCES_PATH = MOD_CONFIG_DIR.resolve("bazaar-resources.json"); private static final Identifier BUNDLED_RESOURCES_ID = Identifier.of(BazaarUtils.MOD_ID, "bazaar-resources.json"); private static final String GITHUB_API_URL = "https://api.github.com/repos/mkram17/Skyblock-Bazaar-Conversions/contents/conversionupdating/bazaar-conversions.json?ref=main"; + /* Cached conversions: lowercase name -> productId */ + @Getter + private static volatile Map nameToProductIdCache = Map.of(); + @Setter + private static volatile boolean conversionsLoaded = false; public static void initialize() { @@ -118,7 +125,7 @@ private static void downloadLatestResources(String downloadUrl, String latestSha MetadataConfig.RESOURCES_SHA = latestSha; ConfigUtil.scheduleConfigSave(); - BazaarDataManager.setConversionsLoaded(false); + ResourceManager.setConversionsLoaded(false); PlayerActionUtil.notifyAll("Successfully updated Bazaar resources!"); } catch (Exception e) { Util.notifyError("Failed to download resources", e); @@ -158,4 +165,44 @@ public static void onClientStart(){ ResourceManager.initialize(); }); } + + /** + * Cached conversion load. Thread-safe (single pass). + */ + public static void ensureConversionsLoaded() { + if (conversionsLoaded) { + return; + } + + // Double-checked guard avoids repeated JSON parsing on the hot path. + synchronized (BazaarDataManager.class) { + if (conversionsLoaded) { + return; + } + + try { + Map mutable = new HashMap<>(); + + var resources = getResourceJson(); + var conversions = resources.getAsJsonObject(); + + for (String key : conversions.keySet()) { + String value = conversions.get(key).getAsString(); + if (value != null) { + mutable.put(value.toLowerCase(Locale.ROOT), key); + } + } + + nameToProductIdCache = Collections.unmodifiableMap(mutable); + conversionsLoaded = true; + + PlayerActionUtil.notifyAll("Loaded bazaarConversions cache: " + nameToProductIdCache.size() + " entries.", NotificationType.BAZAARDATA); + } catch (Exception e) { + Util.notifyError("Failed loading bazaarConversions cache", e); + + nameToProductIdCache = Map.of(); + conversionsLoaded = true; + } + } + } } \ No newline at end of file diff --git a/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/SignInputHelper.java b/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/SignInputHelper.java index 337c0cf2..4eaedb11 100644 --- a/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/SignInputHelper.java +++ b/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/SignInputHelper.java @@ -1,9 +1,9 @@ package com.github.mkram17.bazaarutils.utils.bazaar; -import com.github.mkram17.bazaarutils.data.UserOrdersStorage; +import com.github.mkram17.bazaarutils.utils.storage.UserOrdersStorage; import com.github.mkram17.bazaarutils.events.ChestLoadedEvent; import com.github.mkram17.bazaarutils.utils.Util; -import com.github.mkram17.bazaarutils.utils.bazaar.data.BazaarDataManager; +import com.github.mkram17.bazaarutils.utils.bazaar.data.BazaarDataUtil; import com.github.mkram17.bazaarutils.utils.bazaar.gui.BazaarScreenHandler; import com.github.mkram17.bazaarutils.utils.bazaar.gui.BazaarScreens; import com.github.mkram17.bazaarutils.utils.bazaar.gui.BazaarSlots; @@ -226,7 +226,7 @@ protected String getButtonItemStackSize(TransactionState state) { @Override protected ResolvedInput resolveInput(TransactionState state) { - OptionalDouble price = BazaarDataManager.findItemPriceOptional(state.productId(), getTransactionType()); + OptionalDouble price = BazaarDataUtil.findItemPriceOptional(state.productId(), getTransactionType()); if (price.isEmpty()) { Util.logMessage("Could not retrieve relevant item pricing for " + name + "'s resolved value."); @@ -278,7 +278,7 @@ protected int computeMaxValue(TransactionState state) { .filter(stack -> !stack.isEmpty()) .filter(stack -> Optional.ofNullable(stack.getCustomName()) .map(Text::getString) - .flatMap(BazaarDataManager::findProductIdOptional) + .flatMap(BazaarDataUtil::findProductIdOptional) .map(productId -> productId.equals(state.productId())) .orElse(false)) .mapToInt(ItemStack::getCount) @@ -348,7 +348,7 @@ protected String getButtonItemStackSize(TransactionState state) { @Override protected ResolvedInput resolveInput(TransactionState state) { - OptionalDouble price = BazaarDataManager.findItemPriceOptional(state.productId(), getTransactionType()); + OptionalDouble price = BazaarDataUtil.findItemPriceOptional(state.productId(), getTransactionType()); if (price.isEmpty()) { Util.logMessage("Could not retrieve relevant item pricing for " + name + "'s resolved value."); diff --git a/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/data/BazaarDataManager.java b/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/data/BazaarDataManager.java index 8a9cb156..d47f492f 100644 --- a/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/data/BazaarDataManager.java +++ b/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/data/BazaarDataManager.java @@ -1,22 +1,16 @@ package com.github.mkram17.bazaarutils.utils.bazaar.data; import com.github.mkram17.bazaarutils.BazaarUtils; -import com.github.mkram17.bazaarutils.data.APIUtils; +import com.github.mkram17.bazaarutils.utils.APIUtil; import com.github.mkram17.bazaarutils.events.BazaarDataUpdateEvent; import com.github.mkram17.bazaarutils.misc.NotificationType; -import com.github.mkram17.bazaarutils.utils.annotations.autoregistration.RunOnInit; -import com.github.mkram17.bazaarutils.mixin.AccessorSkyBlockBazaarReply; import com.github.mkram17.bazaarutils.utils.PlayerActionUtil; -import com.github.mkram17.bazaarutils.utils.ResourceManager; import com.github.mkram17.bazaarutils.utils.Util; -import com.github.mkram17.bazaarutils.utils.bazaar.market.order.PriceType; -import com.github.mkram17.bazaarutils.utils.bazaar.market.order.TransactionType; +import com.github.mkram17.bazaarutils.utils.annotations.autoregistration.RunOnInit; +import com.github.mkram17.bazaarutils.utils.bazaar.data.wrappers.APIConversionUtil; +import com.github.mkram17.bazaarutils.utils.bazaar.data.wrappers.CustomBazaarReply; import lombok.Getter; -import lombok.Setter; -import net.hypixel.api.reply.skyblock.SkyBlockBazaarReply; -import java.time.Duration; -import java.util.*; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -25,36 +19,28 @@ public final class BazaarDataManager { - private static final long BASE_INTERVAL_MS = 20_000; - private static final long POST_OFFSET_MS = 500; - private static final long STALE_BACKOFF_MS = 750; - private static final long FAILURE_RETRY_MS = 500; - private static final int STALE_WARNING_THRESHOLD = 5; - @Getter - private static volatile SkyBlockBazaarReply currentReply; + private static volatile CustomBazaarReply currentReply; + @Getter private static volatile long lastSnapshotTs = -1; - private static volatile long lastFetchWallClock = -1; + + private static final BazaarDataSettings BAZAAR_DATA_SETTINGS = new BazaarDataSettings(); private static volatile ScheduledFuture scheduledTask; + // Serializes schedule/cancel so only one pending fetch task exists at a time. private static final Object SCHED_LOCK = new Object(); private static final AtomicInteger consecutiveIdenticalSnapshots = new AtomicInteger(0); - private static final AtomicInteger consecutiveFailures = new AtomicInteger(0); - /* Cached conversions: lowercase name -> productID */ - private static volatile Map nameToProductIdCache = Map.of(); - @Setter - private static volatile boolean conversionsLoaded = false; + private static final AtomicInteger consecutiveFailures = new AtomicInteger(0); @RunOnInit public static void init() { scheduleFetch(0); - PlayerActionUtil.notifyAll("BazaarDataManager initialized (simple fixed-interval poller). Base=" + BASE_INTERVAL_MS + "ms", NotificationType.BAZAARDATA); + PlayerActionUtil.notifyAll("BazaarDataManager initialized (simple fixed-interval poller). Base=" + BAZAAR_DATA_SETTINGS.BASE_INTERVAL_MS + "ms", NotificationType.BAZAARDATA); } - private static void scheduleFetch(long delayMs) { synchronized (SCHED_LOCK) { if (scheduledTask != null && !scheduledTask.isDone()) { @@ -67,258 +53,101 @@ private static void scheduleFetch(long delayMs) { private static void fetchOnceSafely() { try { fetchOnce(); - } catch (Throwable t) { - Util.notifyError("Unexpected error in BazaarDataManager fetch loop", t); - scheduleFetch(FAILURE_RETRY_MS); + } catch (Throwable throwable) { + Util.notifyError("Unexpected error in BazaarDataManager fetch loop", throwable); + scheduleFailureRetry(); } } private static void fetchOnce() { - lastFetchWallClock = System.currentTimeMillis(); - APIUtils.API.getSkyBlockBazaar().whenComplete((reply, throwable) -> { - if (throwable != null) { - consecutiveFailures.incrementAndGet(); - PlayerActionUtil.notifyAll("Fetch failure (" + throwable.getClass().getSimpleName() + "). Retry in " + FAILURE_RETRY_MS + "ms (failures=" + consecutiveFailures.get() + ")", NotificationType.BAZAARDATA); - scheduleFetch(FAILURE_RETRY_MS); - return; - } - if (reply == null || !reply.isSuccess()) { - consecutiveFailures.incrementAndGet(); - PlayerActionUtil.notifyAll("Null/unsuccessful reply. Retry in " + FAILURE_RETRY_MS + "ms (failures=" + consecutiveFailures.get() + ")", NotificationType.BAZAARDATA); - scheduleFetch(FAILURE_RETRY_MS); + APIUtil.API.getSkyBlockBazaar().whenComplete((reply, throwable) -> { + if (throwable != null || !reply.isSuccess()) { + handleFetchFailure( + "Fetch failure (" + throwable.getClass().getSimpleName() + "). Retry in " + BAZAAR_DATA_SETTINGS.FAILURE_RETRY_MS + "ms", + true + ); return; } - consecutiveFailures.set(0); - long snapshotTs = extractLastUpdated(reply); + CustomBazaarReply customReply = APIConversionUtil.fromSkyBlockReply(reply); + + long snapshotTs = customReply.getLastUpdated(); if (snapshotTs <= 0) { - PlayerActionUtil.notifyAll("Invalid lastUpdated <= 0. Retry in " + FAILURE_RETRY_MS + "ms", NotificationType.BAZAARDATA); - scheduleFetch(FAILURE_RETRY_MS); + handleFetchFailure("Invalid lastUpdated <= 0. Retry in " + BAZAAR_DATA_SETTINGS.FAILURE_RETRY_MS + "ms", false); return; } - if (snapshotTs != lastSnapshotTs) { - long previous = lastSnapshotTs; - lastSnapshotTs = snapshotTs; - currentReply = reply; - consecutiveIdenticalSnapshots.set(0); - - EVENT_BUS.post(new BazaarDataUpdateEvent(reply)); - - if (previous != -1) { - PlayerActionUtil.notifyAll("New snapshot " + snapshotTs + " (Δ " + (snapshotTs - previous) + " ms). Scheduling next predicted fetch.", NotificationType.BAZAARDATA); - } else { - PlayerActionUtil.notifyAll("First snapshot " + snapshotTs + " received.", NotificationType.BAZAARDATA); - } + consecutiveFailures.set(0); - scheduleNextFromSnapshot(snapshotTs); - } else { - int identical = consecutiveIdenticalSnapshots.incrementAndGet(); - PlayerActionUtil.notifyAll("Snapshot unchanged (" + snapshotTs + ") x" + identical, NotificationType.BAZAARDATA); - if (identical == STALE_WARNING_THRESHOLD) { - PlayerActionUtil.notifyAll("WARNING: " + identical + " identical snapshots in a row. Server might be lagging or BASE_INTERVAL_MS too short.", NotificationType.BAZAARDATA); - } - scheduleNextFromSnapshot(snapshotTs); - } + handleSnapshotResult(customReply, snapshotTs); + scheduleNextFromSnapshot(snapshotTs); }); } - private static void scheduleNextFromSnapshot(long snapshotTs) { - long now = System.currentTimeMillis(); - long target = snapshotTs + BASE_INTERVAL_MS + POST_OFFSET_MS; - - long delay; - if (now >= target) { - // Past the ideal fetch time; server hasn’t advanced snapshot yet. Don’t spam: back off. - delay = STALE_BACKOFF_MS; - } else { - var typicalDelay = target - now; - delay = Math.max(typicalDelay, STALE_BACKOFF_MS); - } - scheduleFetch(delay); + private static void handleFetchFailure(String messagePrefix, boolean includeFailureCount) { + int failureCount = includeFailureCount ? consecutiveFailures.incrementAndGet() : consecutiveFailures.get(); + String message = includeFailureCount ? messagePrefix + " (failures=" + failureCount + ")" : messagePrefix; + Util.notifyError(message, new Throwable()); + scheduleFailureRetry(); } - private static long extractLastUpdated(SkyBlockBazaarReply reply) { - try { - return ((AccessorSkyBlockBazaarReply) reply).getLastUpdated(); - } catch (Exception e) { - Util.notifyError("Failed to access lastUpdated (mixin+reflection failed)", e); - return -1; - - } - } - - - /** - * Get the number of orders at an exact price for a product & price type. - * @return OptionalInt empty if reply / product / priceType invalid or not found. - */ - public static OptionalInt getOrderCountOptional(String productId, TransactionType transactionType, double price) { - SkyBlockBazaarReply reply = currentReply; - - if (transactionType == null) { - return OptionalInt.empty(); - } - - PriceType priceType = transactionType.getPriceType(); - - if (reply == null || productId == null || priceType == null) { - return OptionalInt.empty(); - } - - try { - SkyBlockBazaarReply.Product product = reply.getProduct(productId); - - if (product == null) { - return OptionalInt.empty(); - } - - List list = switch (priceType) { - case INSTABUY -> product.getBuySummary(); - case INSTASELL -> product.getSellSummary(); - }; - - if (list == null) { - return OptionalInt.empty(); - } - - for (SkyBlockBazaarReply.Product.Summary s : list) { - if (Double.compare(s.getPricePerUnit(), price) == 0) { - return OptionalInt.of((int) s.getOrders()); - } - } - - return OptionalInt.of(0); - } catch (Exception e) { - Util.notifyError("Error in getOrderCountOptional for productID=" + productId, e); - - return OptionalInt.empty(); - } + private static void scheduleFailureRetry() { + scheduleFetch(BAZAAR_DATA_SETTINGS.FAILURE_RETRY_MS); } - /** - * Find the top bazaar price for a product based on the given {@link TransactionType}. - * The returned {@link OptionalDouble} is empty if the reply, product ID, or derived {@link PriceType} - * is {@code null}, if the product cannot be found, or if an exception occurs while resolving the price. - * If the selected summary list exists but is empty, this method returns {@code OptionalDouble.of(0.0)}. - * - * @param productId the bazaar product ID to look up - * @param transactionType the transaction type whose {@link PriceType} controls which summary is queried - * @return an {@link OptionalDouble} containing the resolved price per unit, or empty if unavailable - */ - public static OptionalDouble findItemPriceOptional(String productId, TransactionType transactionType) { - SkyBlockBazaarReply reply = currentReply; - - if (transactionType == null) { - return OptionalDouble.empty(); - } - - PriceType priceType = transactionType.getPriceType(); - - if (reply == null || productId == null || priceType == null) { - return OptionalDouble.empty(); //TODO maybe throw error here instead. Needs testing to make sure it doesn't happen too frequently or at times where it is expected behavior + private static void handleSnapshotResult(CustomBazaarReply reply, long snapshotTs) { + if (snapshotTs != lastSnapshotTs) { + handleNewSnapshot(reply, snapshotTs); + return; } - try { - SkyBlockBazaarReply.Product product = reply.getProduct(productId); - - if (product == null) { - return OptionalDouble.empty(); - } - - return switch (priceType) { - case INSTABUY -> { - List buySummary = product.getBuySummary(); - - if (buySummary == null || buySummary.isEmpty()) { - yield OptionalDouble.of(0.0); - } - - yield OptionalDouble.of(buySummary.getFirst().getPricePerUnit()); - } - case INSTASELL -> { - List sellSummary = product.getSellSummary(); - - if (sellSummary == null || sellSummary.isEmpty()) { - yield OptionalDouble.of(0.0); - } - - yield OptionalDouble.of(sellSummary.getFirst().getPricePerUnit()); - } - }; - } catch (Exception e) { - Util.notifyError("Error in findItemPriceOptional for productID=" + productId, e); - - return OptionalDouble.empty(); - } + handleUnchangedSnapshot(snapshotTs); } - public static Optional findProductIdOptional(String naturalName) { - if (naturalName == null || naturalName.isBlank()) { - return Optional.empty(); - } + private static void handleNewSnapshot(CustomBazaarReply reply, long snapshotTs) { + long previousSnapshotTs = lastSnapshotTs; + lastSnapshotTs = snapshotTs; + currentReply = reply; + consecutiveIdenticalSnapshots.set(0); - ensureConversionsLoaded(); - - return Optional.ofNullable(nameToProductIdCache.get(naturalName.toLowerCase(Locale.ROOT))); - } + EVENT_BUS.post(new BazaarDataUpdateEvent(reply)); - /** - * Cached conversion load. Thread-safe (single pass). - */ - private static void ensureConversionsLoaded() { - if (conversionsLoaded) { + if (previousSnapshotTs != -1) { + PlayerActionUtil.notifyAll( + "New snapshot " + snapshotTs + " (Δ " + (snapshotTs - previousSnapshotTs) + " ms). Scheduling next predicted fetch.", + NotificationType.BAZAARDATA + ); return; } - synchronized (BazaarDataManager.class) { - if (conversionsLoaded) { - return; - } - - try { - Map mutable = new HashMap<>(); - - var resources = ResourceManager.getResourceJson(); - var conversions = resources.getAsJsonObject(); - - for (String key : conversions.keySet()) { - String value = conversions.get(key).getAsString(); - if (value != null) { - mutable.put(value.toLowerCase(Locale.ROOT), key); - } - } - - nameToProductIdCache = Collections.unmodifiableMap(mutable); - conversionsLoaded = true; - - PlayerActionUtil.notifyAll("Loaded bazaarConversions cache: " + nameToProductIdCache.size() + " entries.", NotificationType.BAZAARDATA); - } catch (Exception e) { - Util.notifyError("Failed loading bazaarConversions cache", e); - - nameToProductIdCache = Map.of(); - conversionsLoaded = true; - } - } + PlayerActionUtil.notifyAll("First snapshot " + snapshotTs + " received.", NotificationType.BAZAARDATA); } - public static Optional getCurrentSnapshotAge() { - long ts = lastSnapshotTs; + private static void handleUnchangedSnapshot(long snapshotTs) { + int identicalSnapshotCount = consecutiveIdenticalSnapshots.incrementAndGet(); + PlayerActionUtil.notifyAll("Snapshot unchanged (" + snapshotTs + ") x" + identicalSnapshotCount, NotificationType.BAZAARDATA); - if (ts <= 0) { - return Optional.empty(); + if (identicalSnapshotCount == BAZAAR_DATA_SETTINGS.STALE_WARNING_THRESHOLD) { + PlayerActionUtil.notifyAll( + "WARNING: " + identicalSnapshotCount + " identical snapshots in a row. Server might be lagging or BASE_INTERVAL_MS too short.", + NotificationType.BAZAARDATA + ); } - - return Optional.of(Duration.ofMillis(System.currentTimeMillis() - ts)); } - public static Optional getTimeSinceLastFetchAttempt() { - long f = lastFetchWallClock; + private static void scheduleNextFromSnapshot(long snapshotTs) { + long nowMs = System.currentTimeMillis(); + long expectedNextFetchAtMs = snapshotTs + BAZAAR_DATA_SETTINGS.BASE_INTERVAL_MS + BAZAAR_DATA_SETTINGS.POST_OFFSET_MS; - if (f <= 0) { - return Optional.empty(); + long nextDelayMs; + if (nowMs >= expectedNextFetchAtMs) { + // Past the ideal fetch time; server has not advanced snapshot yet, so back off. + nextDelayMs = BAZAAR_DATA_SETTINGS.STALE_BACKOFF_MS; + } else { + long idealDelayMs = expectedNextFetchAtMs - nowMs; + nextDelayMs = Math.max(idealDelayMs, BAZAAR_DATA_SETTINGS.STALE_BACKOFF_MS); } - return Optional.of(Duration.ofMillis(System.currentTimeMillis() - f)); + scheduleFetch(nextDelayMs); } } \ No newline at end of file diff --git a/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/data/BazaarDataSettings.java b/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/data/BazaarDataSettings.java new file mode 100644 index 00000000..27984a30 --- /dev/null +++ b/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/data/BazaarDataSettings.java @@ -0,0 +1,9 @@ +package com.github.mkram17.bazaarutils.utils.bazaar.data; + +public class BazaarDataSettings { + public final long BASE_INTERVAL_MS = 20_000; + public final long POST_OFFSET_MS = 500; + public final long STALE_BACKOFF_MS = 750; + public final long FAILURE_RETRY_MS = 500; + public final int STALE_WARNING_THRESHOLD = 5; +} diff --git a/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/data/BazaarDataUtil.java b/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/data/BazaarDataUtil.java new file mode 100644 index 00000000..bfc75d80 --- /dev/null +++ b/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/data/BazaarDataUtil.java @@ -0,0 +1,150 @@ +package com.github.mkram17.bazaarutils.utils.bazaar.data; + +import com.github.mkram17.bazaarutils.utils.ResourceManager; +import com.github.mkram17.bazaarutils.utils.Util; +import com.github.mkram17.bazaarutils.utils.bazaar.data.wrappers.CustomBazaarReply; +import com.github.mkram17.bazaarutils.utils.bazaar.data.wrappers.ProductData; +import com.github.mkram17.bazaarutils.utils.bazaar.data.wrappers.ProductOrder; +import com.github.mkram17.bazaarutils.utils.bazaar.market.order.PriceType; +import com.github.mkram17.bazaarutils.utils.bazaar.market.order.TransactionType; +import net.hypixel.api.reply.skyblock.SkyBlockBazaarReply; + +import java.util.List; +import java.util.Locale; +import java.util.Optional; +import java.util.OptionalDouble; +import java.util.OptionalInt; + +public class BazaarDataUtil { + /** + * Get the number of orders at an exact price for a product & price type. + * @return OptionalInt empty if reply / product / priceType invalid or not found. + */ + public static OptionalInt getOrderCountOptional(String productId, TransactionType transactionType, double price) { + CustomBazaarReply reply = BazaarDataManager.getCurrentReply(); + + if (transactionType == null) { + return OptionalInt.empty(); + } + + PriceType priceType = transactionType.getPriceType(); + + if (reply == null || productId == null || priceType == null) { + return OptionalInt.empty(); + } + + try { + ProductData product = reply.getProduct(productId); + + if (product == null) { + return OptionalInt.empty(); + } + + List list = switch (priceType) { + case INSTABUY -> product.getBuyOrders(); + case INSTASELL -> product.getSellOrders(); + }; + + if (list == null) { + return OptionalInt.empty(); + } + + for (ProductOrder s : list) { + if (Double.compare(s.getPricePerUnit(), price) == 0) { + return OptionalInt.of(s.getNumOrders()); + } + } + + return OptionalInt.of(0); + } catch (Exception e) { + Util.notifyError("Error in getOrderCountOptional for productID=" + productId, e); + + return OptionalInt.empty(); + } + } + + /** + * Find the top bazaar price for a product based on the given {@link TransactionType}. + * The returned {@link OptionalDouble} is empty if the reply, product ID, or derived {@link PriceType} + * is {@code null}, if the product cannot be found, or if an exception occurs while resolving the price. + * If the selected summary list exists but is empty, this method returns {@code OptionalDouble.of(0.0)}. + * + * @param productId the bazaar product ID to look up + * @param transactionType the transaction type whose {@link PriceType} controls which summary is queried + * @return an {@link OptionalDouble} containing the resolved price per unit, or empty if unavailable + */ + public static OptionalDouble findItemPriceOptional(String productId, TransactionType transactionType) { + CustomBazaarReply reply = BazaarDataManager.getCurrentReply(); + if (transactionType == null) { + return OptionalDouble.empty(); + } + + PriceType priceType = transactionType.getPriceType(); + + if (reply == null || productId == null || priceType == null) { + return OptionalDouble.empty(); //TODO maybe throw error here instead. Needs testing to make sure it doesn't happen too frequently or at times where it is expected behavior + } + + try { + ProductData product = reply.getProduct(productId); + + if (product == null) { + return OptionalDouble.empty(); + } + + return switch (priceType) { + case INSTABUY -> { + List buySummary = product.getBuyOrders(); + + if (buySummary == null || buySummary.isEmpty()) { + yield OptionalDouble.of(0.0); + } + + yield OptionalDouble.of(buySummary.getFirst().getPricePerUnit()); + } + case INSTASELL -> { + List sellSummary = product.getSellOrders(); + + if (sellSummary == null || sellSummary.isEmpty()) { + yield OptionalDouble.of(0.0); + } + + yield OptionalDouble.of(sellSummary.getFirst().getPricePerUnit()); + } + }; + } catch (Exception e) { + Util.notifyError("Error in findItemPriceOptional for productID=" + productId, e); + + return OptionalDouble.empty(); + } + } + + + /** + * Checks whether the provided string is a known bazaar product ID. + * Uses in-memory data only (current reply + conversion cache). + */ + public static boolean isValidProductId(String productId) { + if (productId == null || productId.isBlank()) { + return false; + } + + CustomBazaarReply reply = BazaarDataManager.getCurrentReply(); + if (reply != null && reply.getProduct(productId) != null) { + return true; + } + + ResourceManager.ensureConversionsLoaded(); + return ResourceManager.getNameToProductIdCache().containsValue(productId); + } + + public static Optional findProductIdOptional(String naturalName) { + if (naturalName == null || naturalName.isBlank()) { + return Optional.empty(); + } + + ResourceManager.ensureConversionsLoaded(); + + return Optional.ofNullable(ResourceManager.getNameToProductIdCache().get(naturalName.toLowerCase(Locale.ROOT))); + } +} diff --git a/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/data/wrappers/APIConversionUtil.java b/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/data/wrappers/APIConversionUtil.java new file mode 100644 index 00000000..897e88b5 --- /dev/null +++ b/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/data/wrappers/APIConversionUtil.java @@ -0,0 +1,69 @@ +package com.github.mkram17.bazaarutils.utils.bazaar.data.wrappers; + +import com.github.mkram17.bazaarutils.mixin.AccessorSkyBlockBazaarReply; +import com.github.mkram17.bazaarutils.utils.bazaar.market.order.Order; +import com.github.mkram17.bazaarutils.utils.bazaar.market.order.PriceType; +import net.hypixel.api.reply.skyblock.SkyBlockBazaarReply; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public final class APIConversionUtil { + + public static CustomBazaarReply fromSkyBlockReply(SkyBlockBazaarReply reply) { + AccessorSkyBlockBazaarReply accessor = (AccessorSkyBlockBazaarReply) reply; + + Map sourceProducts = reply.getProducts(); + Map converted = convertAPIProducts(sourceProducts); + + return new CustomBazaarReply(accessor.getLastUpdated(), converted); + } + + public static Map convertAPIProducts(Map apiProducts) { + if (apiProducts == null || apiProducts.isEmpty()) { + return Map.of(); + } + return apiProducts.entrySet().stream() + .collect(Collectors.toUnmodifiableMap( + Map.Entry::getKey, + e -> fromAPIProduct(e.getKey(), e.getValue()) + )); + } + + public static ProductData fromAPIProduct(String productId, SkyBlockBazaarReply.Product apiProduct) { + List sell = new ArrayList<>(); + List buy = new ArrayList<>(); + + if (apiProduct.getSellSummary() != null) { + var convertedSellSummaries = convertAPIProductSummaries(apiProduct.getSellSummary(), PriceType.INSTASELL); + sell.addAll(convertedSellSummaries); + } + + if (apiProduct.getBuySummary() != null) { + var convertedBuySummaries = convertAPIProductSummaries(apiProduct.getBuySummary(), PriceType.INSTABUY); + buy.addAll(convertedBuySummaries); + } + + return new ProductData(productId, sell, buy); + } + + public static List convertAPIProductSummaries(List apiSummaries, PriceType priceType) { + if (apiSummaries == null || apiSummaries.isEmpty()) { + return List.of(); + } + return apiSummaries.stream() + .map(s -> fromAPIProductSummary(s, priceType)) + .toList(); + } + + public static ProductOrder fromAPIProductSummary(SkyBlockBazaarReply.Product.Summary apiSummary, PriceType priceType) { + return new ProductOrder( + priceType, + apiSummary.getPricePerUnit(), + apiSummary.getAmount(), + apiSummary.getOrders() + ); + } +} diff --git a/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/data/wrappers/CustomBazaarReply.java b/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/data/wrappers/CustomBazaarReply.java new file mode 100644 index 00000000..3fdba9a6 --- /dev/null +++ b/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/data/wrappers/CustomBazaarReply.java @@ -0,0 +1,25 @@ +package com.github.mkram17.bazaarutils.utils.bazaar.data.wrappers; + +import com.github.mkram17.bazaarutils.utils.storage.UserOrdersStorage; +import com.github.mkram17.bazaarutils.utils.bazaar.market.order.Order; +import lombok.Getter; +import net.hypixel.api.reply.AbstractReply; + +import java.util.List; +import java.util.Map; + +public class CustomBazaarReply extends AbstractReply { + @Getter + private final long lastUpdated; + @Getter + private final Map products; + + public CustomBazaarReply(long lastUpdated, Map products) { + this.lastUpdated = lastUpdated; + this.products = products; + } + + public ProductData getProduct(String productId) { + return products.get(productId); + } +} diff --git a/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/data/wrappers/ProductData.java b/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/data/wrappers/ProductData.java new file mode 100644 index 00000000..23ff7782 --- /dev/null +++ b/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/data/wrappers/ProductData.java @@ -0,0 +1,28 @@ +package com.github.mkram17.bazaarutils.utils.bazaar.data.wrappers; + +import lombok.Getter; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class ProductData { + @Getter + private final String productId; + private final List productBuyOrders; + private final List productSellOrders; + + public ProductData(String productId, List productBuyOrders, List productSellOrders) { + this.productId = productId; + this.productBuyOrders = new ArrayList<>(productBuyOrders); + this.productSellOrders = new ArrayList<>(productSellOrders); + } + + public List getBuyOrders() { + return Collections.unmodifiableList(productBuyOrders); + } + + public List getSellOrders() { + return Collections.unmodifiableList(productSellOrders); + } +} diff --git a/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/data/wrappers/ProductOrder.java b/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/data/wrappers/ProductOrder.java new file mode 100644 index 00000000..614bb584 --- /dev/null +++ b/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/data/wrappers/ProductOrder.java @@ -0,0 +1,30 @@ +package com.github.mkram17.bazaarutils.utils.bazaar.data.wrappers; + +import com.github.mkram17.bazaarutils.utils.bazaar.market.order.*; +import lombok.Getter; + +public class ProductOrder { + @Getter + private final PriceType priceType; + @Getter + private final double pricePerUnit; + @Getter + private final long volume; + @Getter + private final long numOrders; + + public ProductOrder(PriceType priceType, double pricePerUnit, long volume, long numOrders) { + this.priceType = priceType; + this.pricePerUnit = pricePerUnit; + this.volume = volume; + this.numOrders = numOrders; + } + + public boolean hasOrders() { + return numOrders >0 && pricePerUnit >0; + } + + public boolean equalsOrder(Order order) { + return order.getTransactionType().getPriceType() == priceType && order.getPricePerItem() == pricePerUnit && order.getVolume() == volume; + } +} diff --git a/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/gui/BazaarScreenHandler.java b/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/gui/BazaarScreenHandler.java index bbd5c1ed..f90b16db 100644 --- a/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/gui/BazaarScreenHandler.java +++ b/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/gui/BazaarScreenHandler.java @@ -1,6 +1,6 @@ package com.github.mkram17.bazaarutils.utils.bazaar.gui; -import com.github.mkram17.bazaarutils.utils.bazaar.data.BazaarDataManager; +import com.github.mkram17.bazaarutils.utils.bazaar.data.BazaarDataUtil; import com.github.mkram17.bazaarutils.utils.bazaar.market.order.OrderInfo; import com.github.mkram17.bazaarutils.utils.bazaar.market.order.TransactionType; import com.github.mkram17.bazaarutils.utils.minecraft.ItemInfo; @@ -70,7 +70,7 @@ public static Optional getDisplayItemName(@NotNull ScreenContext context public static Optional getDisplayProductId(@NotNull ScreenContext context) { return getDisplayItemName(context) - .flatMap(BazaarDataManager::findProductIdOptional); + .flatMap(BazaarDataUtil::findProductIdOptional); } public static Optional getDisplayOrderInfo(@NotNull ScreenContext context) { diff --git a/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/market/order/Order.java b/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/market/order/Order.java index e306dd1b..20264be9 100644 --- a/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/market/order/Order.java +++ b/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/market/order/Order.java @@ -2,7 +2,7 @@ import com.github.mkram17.bazaarutils.config.features.notification.NotificationsConfig; import com.github.mkram17.bazaarutils.config.features.DeveloperConfig; -import com.github.mkram17.bazaarutils.data.UserOrdersStorage; +import com.github.mkram17.bazaarutils.utils.storage.UserOrdersStorage; import com.github.mkram17.bazaarutils.events.BazaarDataUpdateEvent; import com.github.mkram17.bazaarutils.events.UserOrdersChangeEvent; import com.github.mkram17.bazaarutils.events.listener.AbstractListener; diff --git a/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/market/order/OrderInfo.java b/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/market/order/OrderInfo.java index 48895aaf..7180086f 100644 --- a/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/market/order/OrderInfo.java +++ b/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/market/order/OrderInfo.java @@ -1,12 +1,11 @@ package com.github.mkram17.bazaarutils.utils.bazaar.market.order; -import com.github.mkram17.bazaarutils.data.UserOrdersStorage; -import com.github.mkram17.bazaarutils.utils.bazaar.data.BazaarDataManager; +import com.github.mkram17.bazaarutils.utils.storage.UserOrdersStorage; +import com.github.mkram17.bazaarutils.utils.bazaar.data.BazaarDataUtil; import com.github.mkram17.bazaarutils.utils.minecraft.ItemInfo; import com.github.mkram17.bazaarutils.utils.Util; import com.github.mkram17.bazaarutils.utils.bazaar.market.price.PriceInfo; import com.github.mkram17.bazaarutils.utils.bazaar.market.price.PricingPosition; -import com.teamresourceful.resourcefulconfig.api.annotations.ConfigEntry; import lombok.Getter; import lombok.Setter; import lombok.ToString; @@ -49,7 +48,7 @@ public class OrderInfo extends PriceInfo { * Creates a container that tracks market data for a specific Bazaar product. * * @param name display name of the item - * @param side whether this is a buy or sell transaction + * @param side whether this is a buy or sell transaction * @param status status of the order * @param volume quantity of the order * @param pricePerItem current price per unit for the order @@ -64,15 +63,14 @@ public OrderInfo(@Nullable String name, @Nullable TransactionType.Side side, @Nu this.volume = volume; this.tolerance = calculateTolerance(); - BazaarDataManager.findProductIdOptional(name).ifPresent(productId -> this.productID = productId); - validateProductId(productID); + BazaarDataUtil.findProductIdOptional(name).ifPresent(id -> this.productID = id); + validateProductId(); findPricingPosition().ifPresent(pricingPosition -> this.pricingPosition = pricingPosition); } - //TODO validate name/product id with method specifically for that. Maybe can switch findProdIdOpt for non optional version and then rely on validation method. - private void validateProductId(String productId) { - if(productId == null || productId.isBlank()) { - Util.notifyError("Error setting product id for " + this, new Throwable("Product ID cannot be null or blank")); + private void validateProductId() { + if(!BazaarDataUtil.isValidProductId(productID)){ + Util.notifyError("Error setting product id for " + this, new Throwable("Product ID is invalid")); } } @@ -98,7 +96,7 @@ private double calculateTolerance() { * @return {@code true} when a product ID exists for the name */ public static boolean isValidName(String itemName) { - return itemName != null && BazaarDataManager.findProductIdOptional(itemName).isPresent(); + return itemName != null && BazaarDataUtil.findProductIdOptional(itemName).isPresent(); } /** @@ -113,7 +111,7 @@ public Optional findPricingPosition() { double marketPrice = getMarketPrice(transactionType.getSide()); - var orderCountOpt = BazaarDataManager.getOrderCountOptional(productID, getTransactionType(), getPricePerItem()); + var orderCountOpt = BazaarDataUtil.getOrderCountOptional(productID, getTransactionType(), getPricePerItem()); if (orderCountOpt.isEmpty()) { return Optional.empty(); diff --git a/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/market/order/OrderUpdater.java b/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/market/order/OrderUpdater.java index 7b3d2855..fb34a3b9 100644 --- a/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/market/order/OrderUpdater.java +++ b/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/market/order/OrderUpdater.java @@ -1,6 +1,6 @@ package com.github.mkram17.bazaarutils.utils.bazaar.market.order; -import com.github.mkram17.bazaarutils.data.UserOrdersStorage; +import com.github.mkram17.bazaarutils.utils.storage.UserOrdersStorage; import com.github.mkram17.bazaarutils.events.ChestLoadedEvent; import com.github.mkram17.bazaarutils.utils.Util; import com.github.mkram17.bazaarutils.utils.bazaar.gui.BazaarScreens; diff --git a/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/market/order/OrderUtil.java b/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/market/order/OrderUtil.java index 657c3fa1..b167df41 100644 --- a/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/market/order/OrderUtil.java +++ b/src/main/java/com/github/mkram17/bazaarutils/utils/bazaar/market/order/OrderUtil.java @@ -1,11 +1,11 @@ package com.github.mkram17.bazaarutils.utils.bazaar.market.order; -import com.github.mkram17.bazaarutils.data.UserOrdersStorage; +import com.github.mkram17.bazaarutils.utils.storage.UserOrdersStorage; import com.github.mkram17.bazaarutils.events.UserOrdersChangeEvent; import com.github.mkram17.bazaarutils.misc.NotificationType; import com.github.mkram17.bazaarutils.utils.PlayerActionUtil; import com.github.mkram17.bazaarutils.utils.Util; -import com.github.mkram17.bazaarutils.utils.bazaar.data.BazaarDataManager; +import com.github.mkram17.bazaarutils.utils.bazaar.data.BazaarDataUtil; import com.github.mkram17.bazaarutils.utils.bazaar.gui.BazaarScreens; import com.github.mkram17.bazaarutils.utils.bazaar.market.price.PricingPosition; import com.github.mkram17.bazaarutils.utils.minecraft.gui.ScreenManager; @@ -74,8 +74,8 @@ public static double getPriceForPosition(String productID, PricingPosition prici return -1; } - OptionalDouble marketSellPriceOpt = BazaarDataManager.findItemPriceOptional(productID, TransactionType.of(TransactionType.Side.SELL, TransactionType.Method.ORDER)); - OptionalDouble marketBuyPriceOpt = BazaarDataManager.findItemPriceOptional(productID, TransactionType.of(TransactionType.Side.BUY, TransactionType.Method.ORDER)); + OptionalDouble marketSellPriceOpt = BazaarDataUtil.findItemPriceOptional(productID, TransactionType.of(TransactionType.Side.SELL, TransactionType.Method.ORDER)); + OptionalDouble marketBuyPriceOpt = BazaarDataUtil.findItemPriceOptional(productID, TransactionType.of(TransactionType.Side.BUY, TransactionType.Method.ORDER)); if(marketBuyPriceOpt.isEmpty() || marketSellPriceOpt.isEmpty()) { Util.notifyError("Could not resolve market prices for " + productID + " when calculating price for position. Buy price present: " + marketBuyPriceOpt.isPresent() + " Sell price present: " + marketSellPriceOpt.isPresent(), new Exception("Price resolution error")); diff --git a/src/main/java/com/github/mkram17/bazaarutils/utils/minecraft/PlayerSlots.java b/src/main/java/com/github/mkram17/bazaarutils/utils/minecraft/PlayerSlots.java index 408d8638..59a69183 100644 --- a/src/main/java/com/github/mkram17/bazaarutils/utils/minecraft/PlayerSlots.java +++ b/src/main/java/com/github/mkram17/bazaarutils/utils/minecraft/PlayerSlots.java @@ -1,6 +1,6 @@ package com.github.mkram17.bazaarutils.utils.minecraft; -import com.github.mkram17.bazaarutils.utils.bazaar.data.BazaarDataManager; +import com.github.mkram17.bazaarutils.utils.bazaar.data.BazaarDataUtil; import com.github.mkram17.bazaarutils.utils.minecraft.gui.ScreenManager; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.ingame.GenericContainerScreen; @@ -27,7 +27,7 @@ public static Optional findScreenSlotByProductId(String productId) { ItemStack stack = mainStacks.get(i); boolean matches = !stack.isEmpty() - && BazaarDataManager.findProductIdOptional(stack.getName().getString()) + && BazaarDataUtil.findProductIdOptional(stack.getName().getString()) .map(id -> id.equals(productId)) .orElse(false); diff --git a/src/main/java/com/github/mkram17/bazaarutils/data/BazaarLimitsStorage.java b/src/main/java/com/github/mkram17/bazaarutils/utils/storage/BazaarLimitsStorage.java similarity index 83% rename from src/main/java/com/github/mkram17/bazaarutils/data/BazaarLimitsStorage.java rename to src/main/java/com/github/mkram17/bazaarutils/utils/storage/BazaarLimitsStorage.java index a7596c06..166c4b06 100644 --- a/src/main/java/com/github/mkram17/bazaarutils/data/BazaarLimitsStorage.java +++ b/src/main/java/com/github/mkram17/bazaarutils/utils/storage/BazaarLimitsStorage.java @@ -1,7 +1,6 @@ -package com.github.mkram17.bazaarutils.data; +package com.github.mkram17.bazaarutils.utils.storage; import com.github.mkram17.bazaarutils.features.gui.overlays.BazaarLimitsVisualizer; -import com.github.mkram17.bazaarutils.utils.storage.DataStorage; import com.google.gson.reflect.TypeToken; import java.lang.reflect.Type; import java.util.ArrayList; diff --git a/src/main/java/com/github/mkram17/bazaarutils/data/BookmarksStorage.java b/src/main/java/com/github/mkram17/bazaarutils/utils/storage/BookmarksStorage.java similarity index 81% rename from src/main/java/com/github/mkram17/bazaarutils/data/BookmarksStorage.java rename to src/main/java/com/github/mkram17/bazaarutils/utils/storage/BookmarksStorage.java index 504c436f..14b3b70f 100644 --- a/src/main/java/com/github/mkram17/bazaarutils/data/BookmarksStorage.java +++ b/src/main/java/com/github/mkram17/bazaarutils/utils/storage/BookmarksStorage.java @@ -1,7 +1,6 @@ -package com.github.mkram17.bazaarutils.data; +package com.github.mkram17.bazaarutils.utils.storage; import com.github.mkram17.bazaarutils.features.gui.buttons.bookmarks.Bookmark; -import com.github.mkram17.bazaarutils.utils.storage.DataStorage; import com.google.gson.reflect.TypeToken; import java.lang.reflect.Type; import java.util.ArrayList; diff --git a/src/main/java/com/github/mkram17/bazaarutils/data/UserOrdersStorage.java b/src/main/java/com/github/mkram17/bazaarutils/utils/storage/UserOrdersStorage.java similarity index 81% rename from src/main/java/com/github/mkram17/bazaarutils/data/UserOrdersStorage.java rename to src/main/java/com/github/mkram17/bazaarutils/utils/storage/UserOrdersStorage.java index 018b605c..13b5c18d 100644 --- a/src/main/java/com/github/mkram17/bazaarutils/data/UserOrdersStorage.java +++ b/src/main/java/com/github/mkram17/bazaarutils/utils/storage/UserOrdersStorage.java @@ -1,7 +1,6 @@ -package com.github.mkram17.bazaarutils.data; +package com.github.mkram17.bazaarutils.utils.storage; import com.github.mkram17.bazaarutils.utils.bazaar.market.order.Order; -import com.github.mkram17.bazaarutils.utils.storage.DataStorage; import com.google.gson.reflect.TypeToken; import java.lang.reflect.Type; import java.util.ArrayList;