Skip to content

GH-61 Add balance top command #67

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 28 commits into
base: master
Choose a base branch
from
Open

GH-61 Add balance top command #67

wants to merge 28 commits into from

Conversation

eripe14
Copy link
Member

@eripe14 eripe14 commented Feb 4, 2025

As @vLuckyyy:

I refactored generally this code.
The code is so fast, I decided to remove the time top refresh.

Screenshots:

image
image

2025-02-09.19-02-09.mp4

@eripe14 eripe14 requested review from Rollczi and vLuckyyy February 4, 2025 12:24
Copy link

coderabbitai bot commented Feb 4, 2025

Walkthrough

The changes add a leaderboard feature to the economy system. New classes and records handle leaderboard data and commands, letting players view rankings based on account balances. The account manager now tracks accounts by balance and supports asynchronous leaderboard queries. Configuration options and a permission constant were added to control leaderboard behavior and access. New message templates provide clear feedback about leaderboard info. Benchmark tests were introduced to measure leaderboard performance. Some minor updates were made to build files and existing code to support these features smoothly. Overall, the update focuses on adding leaderboard support and improving related user interactions.

Tip

⚡💬 Agentic Chat (Pro Plan, General Availability)
  • We're introducing multi-step agentic chat in review comments and issue comments, within and outside of PR's. This feature enhances review and issue discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments and add commits to existing pull requests.

📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 588160d and 5ca3941.

📒 Files selected for processing (2)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/EconomyBukkitPlugin.java (5 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/vault/VaultEconomyProvider.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/EconomyBukkitPlugin.java
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (8)
eternaleconomy-core/src/main/java/com/eternalcode/economy/vault/VaultEconomyProvider.java (8)

47-49: Nice refactoring!

Using the helper method getPlayerAccount makes the code cleaner.


52-54: Good simplification of world-specific methods

Delegating to the non-world methods reduces code duplication and makes maintenance easier.

Also applies to: 63-65, 74-76, 91-93, 108-110, 118-120


57-60: Good null handling

Checking for null and returning 0.0 as default is a safe approach.


68-71: Proper null check

Adding a null check before comparing the balance prevents potential errors.


79-88: Good error handling

Explicit null checks and appropriate error responses make the code more robust.

Also applies to: 96-105


112-115: Simple and effective

Using the helper method simplifies account creation verification.


122-128: Helpful utility methods

These helper methods centralize account retrieval logic and make the code more maintainable.


130-136: Clean response handling

Creating helper methods for responses reduces duplication and improves readability.

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@eripe14 eripe14 changed the title Add top balance command (#61) GH-67 Add top balance command (#61) Feb 4, 2025
@eripe14 eripe14 linked an issue Feb 4, 2025 that may be closed by this pull request
@eripe14 eripe14 changed the title GH-67 Add top balance command (#61) GH-67 Add top balance command Feb 4, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (4)
eternaleconomy-core/src/main/java/com/eternalcode/economy/config/implementation/PluginConfig.java (1)

26-27: Consider adding size limits

The top balance size should probably have minimum and maximum values to prevent performance issues.

     @Comment("Top balance size")
+    @Comment("Min: 1, Max: 100")
     public int topBalanceSize = 10;
eternaleconomy-core/src/main/java/com/eternalcode/economy/command/player/TopBalanceCommand.java (1)

16-16: Remove unused import

The Random class is imported but never used.

-import java.util.Random;
eternaleconomy-core/src/main/java/com/eternalcode/economy/config/implementation/messages/MessagesPlayerSubSection.java (1)

4-4: Remove unused import

The Not class is imported but never used.

-import com.j256.ormlite.stmt.query.Not;
eternaleconomy-core/src/main/java/com/eternalcode/economy/account/AccountManager.java (1)

102-108: Consider caching account positions

The current implementation works but might be slow for many accounts. Consider caching positions or using an index for better performance.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4a2a24e and 5b91537.

📒 Files selected for processing (7)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/EconomyBukkitPlugin.java (2 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/EconomyPermissionConstant.java (1 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/account/AccountManager.java (3 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/account/AccountPosition.java (1 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/command/player/TopBalanceCommand.java (1 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/config/implementation/PluginConfig.java (1 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/config/implementation/messages/MessagesPlayerSubSection.java (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/account/AccountPosition.java
🔇 Additional comments (3)
eternaleconomy-core/src/main/java/com/eternalcode/economy/command/player/TopBalanceCommand.java (1)

51-61: Add null check for player names

Some accounts might have null names, which could cause issues when displaying the list.

     for (Account topAccount : this.accountManager.getSortedTopAccounts(topBalanceSize)) {
+        String playerName = topAccount.name() != null ? topAccount.name() : "Unknown";
         this.noticeService.create()
             .notice(messageConfig -> messageConfig.player.topBalanceEntry)
             .placeholder("{POSITION}", String.valueOf(position))
-            .placeholder("{PLAYER}", topAccount.name())
+            .placeholder("{PLAYER}", playerName)
             .placeholder("{BALANCE}", this.decimalFormatter.format(topAccount.balance()))
             .player(uuid)
             .send();
✅ Verification successful

Null Check for Player Names Verified

The new code correctly handles potential null player names by using a ternary operator to provide a default value. This approach helps avoid issues when a player's name isn't available.

🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts or web queries found

eternaleconomy-core/src/main/java/com/eternalcode/economy/account/AccountManager.java (1)

70-74: LGTM!

Making the save method public is a good choice for better integration with other features.

eternaleconomy-core/src/main/java/com/eternalcode/economy/EconomyBukkitPlugin.java (1)

132-133: LGTM!

The TopBalanceCommand is properly registered with all needed dependencies.

@vLuckyyy vLuckyyy changed the title GH-67 Add top balance command GH-61 Add top balance command Feb 4, 2025
@vLuckyyy vLuckyyy changed the title GH-61 Add top balance command GH-61 Add balance top command Feb 4, 2025
Copy link
Member

@vLuckyyy vLuckyyy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current implementation of /baltop returns a leaderboard based only on online players. However, industry-standard practice (and community expectations) dictate that leaderboards should include all registered accounts, both online and offline.

@EternalCodeTeam EternalCodeTeam deleted a comment from coderabbitai bot Feb 4, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (7)
eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardUpdater.java (2)

11-14: Consider adding error handling

The run method should catch and handle any exceptions that might occur during the update.

Here's a simple way to handle errors:

 @Override
 public void run() {
+    try {
         this.leaderboardService.updateTopAccounts();
+    } catch (Exception e) {
+        // Log the error or handle it appropriately
+        e.printStackTrace();
+    }
 }

3-3: Add class documentation

Consider adding a simple comment to explain what this updater does and how often it runs.

Add this documentation:

+/**
+ * Updates the player balance leaderboard periodically when run.
+ */
 public class LeaderboardUpdater implements Runnable {
eternaleconomy-core/src/main/java/com/eternalcode/economy/config/implementation/PluginConfig.java (1)

27-29: Add validation for leaderboard size.

The default value of 10 looks good, but we should add checks to prevent very large or negative values.

     @Comment("Leaderboard size")
-    public int leaderboardSize = 10;
+    @Min(1)
+    @Max(100)
+    public int leaderboardSize = 10;
eternaleconomy-core/src/main/java/com/eternalcode/economy/format/DurationFormatterUtil.java (1)

17-21: Make the formatter more efficient

Creating a new formatter for each call can slow things down. Let's cache it instead.

+    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern(PATTERN_FORMAT);
+
     public static String format(Instant instant) {
-        ZonedDateTime zonedDateTime = instant.atZone(ZoneId.of(ZONE));
-        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(PATTERN_FORMAT);
-        return formatter.format(zonedDateTime);
+        return FORMATTER.format(instant.atZone(ZoneId.of(ZONE)));
     }
eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardService.java (2)

31-39: Simplify stream operations

The code creates a PriorityQueue and then streams it again, which is unnecessary.

Here's a simpler version:

-            accounts.stream()
-                .collect(Collectors.toCollection(() ->
-                    new PriorityQueue<>((a1, a2) -> a2.balance().compareTo(a1.balance()))
-                ))
-                .stream()
-                .limit(this.pluginConfig.leaderboardSize)
-                .forEach(account -> {
-                    this.topAccounts.computeIfAbsent(account.balance(), (k) -> new ArrayList<>()).add(account);
-                });
+            accounts.stream()
+                .sorted((a1, a2) -> a2.balance().compareTo(a1.balance()))
+                .limit(this.pluginConfig.leaderboardSize)
+                .forEach(account -> 
+                    this.topAccounts.computeIfAbsent(account.balance(), k -> new ArrayList<>()).add(account)
+                );

59-67: Consider caching account positions

Loading all accounts for each position check might be inefficient for frequent requests.

Consider caching positions during loadTopAccounts and updating them with each refresh.

eternaleconomy-core/src/main/java/com/eternalcode/economy/EconomyBukkitPlugin.java (1)

104-110: Simplify update interval calculation

The conversion of Duration to ticks could be clearer.

Consider creating a utility method for converting Duration to ticks:

+    private long durationToTicks(Duration duration) {
+        return duration.toSeconds() * 20L;
+    }

     server.getScheduler().runTaskTimerAsynchronously(
         this,
         new LeaderboardUpdater(leaderboardService),
         0L,
-        pluginConfig.leaderboardUpdateInterval.toSeconds() * 20L
+        durationToTicks(pluginConfig.leaderboardUpdateInterval)
     );
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d62f4fd and 98fe767.

📒 Files selected for processing (8)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/EconomyBukkitPlugin.java (4 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/account/AccountManager.java (2 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/command/player/TopBalanceCommand.java (1 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/config/implementation/PluginConfig.java (2 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/config/implementation/messages/MessagesPlayerSubSection.java (1 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/format/DurationFormatterUtil.java (1 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardService.java (1 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardUpdater.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/account/AccountManager.java
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/command/player/TopBalanceCommand.java
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/config/implementation/messages/MessagesPlayerSubSection.java
🧰 Additional context used
🪛 GitHub Actions: Build
eternaleconomy-core/src/main/java/com/eternalcode/economy/EconomyBukkitPlugin.java

[error] 102-102: cannot find symbol: method test() in variable accountManager of type AccountManager

🔇 Additional comments (5)
eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardUpdater.java (1)

1-16: Nice and clean implementation!

The class structure looks good with proper dependency injection.

eternaleconomy-core/src/main/java/com/eternalcode/economy/config/implementation/PluginConfig.java (2)

33-34: Consider performance impact of update interval.

A 5-minute update interval might be too frequent for servers with many players. Consider increasing the default or adding a note about adjusting based on server size.

Would you like me to suggest a more conservative default value based on typical server configurations?


30-32: Nice work on the configuration clarity!

The comment and boolean flag for showing update time is well-documented and user-friendly.

eternaleconomy-core/src/main/java/com/eternalcode/economy/format/DurationFormatterUtil.java (1)

13-15: Nice work on the constructor!

Good job preventing instantiation with a clear error message.

eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardService.java (1)

21-26: Consider potential race condition in constructor

The lastUpdated timestamp is set before loadTopAccounts finishes loading the data asynchronously. This might give incorrect information about when the data was actually loaded.

Move line 25 into the completion callback of loadTopAccounts.

Copy link
Member

@vLuckyyy vLuckyyy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition, after creating a leaderboard package, it suggests removing the word top from all places, for example:

updateTopAccouns -> updateLeaderboard
getTopAccouns -> somthing like that: calculateLeaderboard

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (7)
eternaleconomy-core/src/main/java/com/eternalcode/economy/config/implementation/PluginConfig.java (2)

36-38: Consider allowing longer update intervals.

5 minutes is good for small servers, but might be a bit frequent for larger ones.

-    public Duration leaderboardUpdateInterval = Duration.ofMinutes(5);
+    public Duration leaderboardUpdateInterval = Duration.ofMinutes(15);

39-47: Great documentation for time settings!

The link to time zones and the clear pattern format explanation are super helpful. Just one small suggestion - consider adding an example of the formatted output in the comments.

     @Comment({
         "# Pattern format for time",
-        "# Where 'dd' is day, 'MM' is month, 'yyyy' is year, 'HH' is hour, 'mm' is minute, 'ss' is second"
+        "# Where 'dd' is day, 'MM' is month, 'yyyy' is year, 'HH' is hour, 'mm' is minute, 'ss' is second",
+        "# Example output: 25.02.2025 14:30:45"
     })
eternaleconomy-core/src/main/java/com/eternalcode/economy/EconomyBukkitPlugin.java (1)

105-109: Consider adding a small initial delay

Starting the leaderboard updates immediately might be too early. A small initial delay would give the system time to properly initialize.

-            Duration.ZERO,
+            Duration.ofSeconds(5),
             pluginConfig.leaderboardUpdateInterval
eternaleconomy-core/src/main/java/com/eternalcode/economy/format/DurationFormatter.java (1)

12-16: Consider validating config values in constructor

The constructor could validate the timezone and pattern format when the class is created.

Here's a suggestion:

 private final PluginConfig pluginConfig;

 public DurationFormatter(PluginConfig pluginConfig) {
+    if (pluginConfig == null) {
+        throw new IllegalArgumentException("Config cannot be null");
+    }
+    // Validate timezone and pattern format
+    try {
+        ZoneId.of(pluginConfig.timeZone);
+        DateTimeFormatter.ofPattern(pluginConfig.timePatternFormat);
+    } catch (Exception e) {
+        throw new IllegalArgumentException("Invalid timezone or pattern format in config", e);
+    }
     this.pluginConfig = pluginConfig;
 }
eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardService.java (1)

60-69: Optimize position calculation

Consider reusing the already sorted data from topAccounts instead of re-sorting all accounts.

 public CompletableFuture<LeaderboardPosition> getLeaderboardPosition(Account targetAccount) {
-    return this.accountRepository.getAllAccounts().thenApply(accounts -> {
-        List<Account> sorted = accounts.stream()
-            .sorted(Comparator.comparing(Account::balance).reversed())
-            .toList();
-        int position = sorted.indexOf(targetAccount) + 1;
+    return CompletableFuture.completedFuture(
+        new LeaderboardPosition(
+            targetAccount,
+            findPositionInTopAccounts(targetAccount)
+        )
+    );
 }

+private int findPositionInTopAccounts(Account targetAccount) {
+    int position = 1;
+    for (Map.Entry<BigDecimal, List<Account>> entry : topAccounts.entrySet()) {
+        if (entry.getValue().contains(targetAccount)) {
+            return position;
+        }
+        position += entry.getValue().size();
+    }
+    return position;
 }
eternaleconomy-core/src/main/java/com/eternalcode/economy/account/AccountManager.java (1)

9-10: Remove unused imports

The Collection and Collections imports appear to be unused after removing the getAccounts method.

-import java.util.Collection;
-import java.util.Collections;
eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardCommand.java (1)

42-82: Make position tracking more robust

The position counter could get out of sync if the leaderboard updates while processing entries.

Consider getting positions directly from the leaderboard entries:

-int position = 1;
+List<Account> leaderboard = this.leaderboardService.getLeaderboard().stream().toList();
 
-for (Account topAccount : this.leaderboardService.getLeaderboard()) {
+for (int i = 0; i < leaderboard.size(); i++) {
+    Account topAccount = leaderboard.get(i);
+    int position = i + 1;
     this.noticeService.create()
         .notice(messageConfig -> messageConfig.player.leaderboardEntry)
         .placeholder("{POSITION}", String.valueOf(position))
         .placeholder("{PLAYER}", topAccount.name())
         .placeholder("{BALANCE}", this.decimalFormatter.format(topAccount.balance()))
         .player(uuid)
         .send();
-
-    position++;
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 98fe767 and adb6645.

📒 Files selected for processing (9)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/EconomyBukkitPlugin.java (4 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/account/AccountManager.java (1 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/config/implementation/PluginConfig.java (2 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/config/implementation/messages/MessagesPlayerSubSection.java (1 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/format/DurationFormatter.java (1 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardCommand.java (1 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardPosition.java (1 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardService.java (1 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardUpdater.java (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardPosition.java
🚧 Files skipped from review as they are similar to previous changes (2)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardUpdater.java
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/config/implementation/messages/MessagesPlayerSubSection.java
🧰 Additional context used
📓 Learnings (1)
eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardService.java (1)
Learnt from: vLuckyyy
PR: EternalCodeTeam/EternalEconomy#67
File: eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardService.java:1-1
Timestamp: 2025-02-04T20:41:28.072Z
Learning: In leaderboard implementations, when grouping by balance, apply size limits after grouping to avoid unfairly clipping accounts with the same balance. PriorityQueue should be avoided in streams as it doesn't guarantee ordered traversal - use simple sorting instead.
🔇 Additional comments (5)
eternaleconomy-core/src/main/java/com/eternalcode/economy/config/implementation/PluginConfig.java (2)

27-29: Nice addition of the leaderboard size config!

The default value of 10 is a good choice for most use cases.


30-35: Good user experience settings!

These visibility options give users nice flexibility in how the leaderboard appears.

eternaleconomy-core/src/main/java/com/eternalcode/economy/EconomyBukkitPlugin.java (1)

104-109: Update scheduler usage for Folia compatibility

The current scheduler implementation might not work with Folia. Consider using the scheduler pattern from the provided example:

Scheduler scheduler = EconomySchedulerAdapter.getAdaptiveScheduler(this);

eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardService.java (2)

44-49: ⚠️ Potential issue

Apply size limit to groups, not individual accounts

The current implementation might exclude accounts that have the same balance as included accounts.

Here's a better approach:

 public Collection<Account> getLeaderboard() {
-    return this.topAccounts.values().stream()
-        .flatMap(List::stream)
-        .limit(this.pluginConfig.leaderboardSize)
-        .toList();
+    return this.topAccounts.values().stream()
+        .limit(this.pluginConfig.leaderboardSize)
+        .flatMap(List::stream)
+        .toList();
 }

Likely invalid or redundant comment.


31-42: ⚠️ Potential issue

Fix leaderboard grouping logic

The current implementation may unfairly exclude accounts with the same balance. Also, the pre-sorting is unnecessary since TreeMap already maintains order.

Try this simpler approach:

 private void loadLeaderboard() {
     this.accountRepository.getAllAccounts().thenAccept(accounts -> {
         this.topAccounts.clear();
         this.topAccounts.putAll(accounts.stream()
-            .sorted((a1, a2) -> a2.balance().compareTo(a1.balance()))
             .collect(Collectors.groupingBy(
                 Account::balance,
                 () -> new TreeMap<>(Comparator.reverseOrder()),
                 Collectors.toList()
             )));
     });
 }

Likely invalid or redundant comment.

Copy link
Member

@vLuckyyy vLuckyyy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll do the rest of the review in the morning.

@Rollczi
Copy link
Member

Rollczi commented Feb 13, 2025

Jak dla mnie przepychanki w review bo "eripe"
Tak na poważnie to w tych widełkach ten kod miał jeszcze jakiś sens:
image
Nie żeby był to szczyt inżynierii ale jak patrzę na historię to nie było lepszych momentów (jeśli chodzi o indexy). Obecnie indexy nie mają za dużo sensów, wyciągamy całą bazę danych i klonujemy kolekcję z 3 razy zanim to zostanie w ogóle odfiltorawne w komendzie. Jeśli chodzi o JMH który został dodany to mało co reprezentuje.

Jak dla mnie to index powinien być w AccountManager bo tam dokonujemy operacji na danych lub jeśli chcecie pobierać dane zawsze z repo to index in-memory jest do śmietnika bo DB ma swoje indexy.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (3)
eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardService.java (2)

19-31: Optimize memory usage with pagination.

Loading all accounts at once could cause memory issues with large datasets. Consider implementing pagination at the data source level.

-    public CompletableFuture<List<LeaderboardEntry>> getLeaderboard() {
+    public CompletableFuture<List<LeaderboardEntry>> getLeaderboard(int limit) {
         List<LeaderboardEntry> entries = new ArrayList<>();
         int position = 1;
+        int count = 0;

         NavigableMap<?, Set<Account>> balanceTiers = accountManager.getAccountsByBalance();
         for (Set<Account> accounts : balanceTiers.values()) {
             for (Account account : accounts) {
+                if (count >= limit) {
+                    return CompletableFuture.completedFuture(entries);
+                }
                 entries.add(new LeaderboardEntry(account, position));
+                count++;
             }
             position += accounts.size();
         }
         return CompletableFuture.completedFuture(entries);
     }

46-56: Optimize position lookup.

Consider using the account's balance to directly access the relevant tier instead of iterating through all tiers.

     public CompletableFuture<LeaderboardEntry> getLeaderboardPosition(Account target) {
         int position = 1;
         NavigableMap<?, Set<Account>> balanceTiers = accountManager.getAccountsByBalance();
+        Set<Account> targetTier = balanceTiers.get(target.balance());
+        if (targetTier != null && targetTier.contains(target)) {
+            return CompletableFuture.completedFuture(new LeaderboardEntry(target, position));
+        }
-        for (Set<Account> accounts : balanceTiers.values()) {
-            if (accounts.contains(target)) {
-                return CompletableFuture.completedFuture(new LeaderboardEntry(target, position));
-            }
-            position += accounts.size();
-        }
         return CompletableFuture.completedFuture(new LeaderboardEntry(target, -1));
     }
eternaleconomy-core/src/main/java/com/eternalcode/economy/account/AccountManager.java (1)

68-93: Reduce code duplication in create methods.

Both create methods share similar logic for updating collections. Consider extracting the common code into a private helper method.

+    private void updateCollections(Account account) {
+        this.accountByUniqueId.put(account.uuid(), account);
+        this.accountByName.put(account.name(), account);
+        this.accountIndex.put(account.name(), account);
+        this.accountsByBalance.computeIfAbsent(account.balance(), k -> ConcurrentHashMap.newKeySet()).add(account);
+    }

     public Account create(UUID uuid, String name) {
         if (this.accountByUniqueId.containsKey(uuid) || this.accountByName.containsKey(name)) {
             throw new IllegalArgumentException("Account with UUID " + uuid + " already exists");
         }

         Account account = new Account(uuid, name, BigDecimal.ZERO);
-        this.accountByUniqueId.put(uuid, account);
-        this.accountByName.put(name, account);
-        this.accountIndex.put(name, account);
-        this.accountsByBalance.computeIfAbsent(account.balance(), k -> new HashSet<>()).add(account);
+        updateCollections(account);
         return account;
     }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bd40e8f and 152f2a6.

📒 Files selected for processing (9)
  • eternaleconomy-core/src/jmh/java/com/eternalcode/economy/account/AccountBenchmark.java (1 hunks)
  • eternaleconomy-core/src/jmh/java/com/eternalcode/economy/leaderboard/LeaderboardServiceBenchmark.java (1 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/EconomyBukkitPlugin.java (4 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/account/AccountManager.java (5 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/config/implementation/messages/MessagesPlayerSubSection.java (2 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardCommand.java (1 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardEntry.java (1 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardPage.java (1 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardService.java (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardEntry.java
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardPage.java
🚧 Files skipped from review as they are similar to previous changes (5)
  • eternaleconomy-core/src/jmh/java/com/eternalcode/economy/account/AccountBenchmark.java
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/EconomyBukkitPlugin.java
  • eternaleconomy-core/src/jmh/java/com/eternalcode/economy/leaderboard/LeaderboardServiceBenchmark.java
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardCommand.java
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/config/implementation/messages/MessagesPlayerSubSection.java
🧰 Additional context used
🧠 Learnings (1)
eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardService.java (1)
Learnt from: vLuckyyy
PR: EternalCodeTeam/EternalEconomy#67
File: eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardService.java:1-1
Timestamp: 2025-02-04T20:41:28.072Z
Learning: In leaderboard implementations, when grouping by balance, apply size limits after grouping to avoid unfairly clipping accounts with the same balance. PriorityQueue should be avoided in streams as it doesn't guarantee ordered traversal - use simple sorting instead.
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (1)
eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardService.java (1)

33-44: Well-implemented pagination logic!

The pagination implementation handles edge cases properly and uses appropriate mathematical operations for page calculations.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
eternaleconomy-core/src/jmh/java/com/eternalcode/economy/leaderboard/LeaderboardServiceBenchmark.java (1)

37-59: Improve account creation strategy.

Creating accounts with random balances might not reflect real-world balance distribution patterns. Also, storing every 100,000th account for position testing could miss edge cases.

Consider:

-            if (i % 100_000 == 0) {
+            // Store accounts at different percentiles for better coverage
+            if (i % (ACCOUNTS_COUNT / 20) == 0) {
                 targetAccounts.add(account);
             }
eternaleconomy-core/src/main/java/com/eternalcode/economy/account/AccountManager.java (2)

83-94: Consider combining the create methods

You have two similar create methods. The new one could reuse code from the existing one to avoid duplication.

-    public Account create(Account account) {
-        if (this.accountByUniqueId.containsKey(account.uuid())) {
-            throw new IllegalArgumentException("Account already exists: " + account.uuid());
-        }
-
-        this.accountByUniqueId.put(account.uuid(), account);
-        this.accountByName.put(account.name(), account);
-        this.accountIndex.put(account.name(), account);
-        this.accountsByBalance.put(account.balance(), account);
-
-        return account;
-    }
+    public Account create(Account account) {
+        if (this.accountByUniqueId.containsKey(account.uuid())) {
+            throw new IllegalArgumentException("Account already exists: " + account.uuid());
+        }
+        return this.save(account);
+    }

128-134: Consider protecting the balance data

Returning the TreeMultimap directly could let other code modify it. Maybe return an unmodifiable view instead?

-    public TreeMultimap<BigDecimal, Account> getAccountsByBalance() {
-        return this.accountsByBalance;
+    public TreeMultimap<BigDecimal, Account> getAccountsByBalance() {
+        return TreeMultimap.create(this.accountsByBalance);
     }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 152f2a6 and b1c0eb4.

📒 Files selected for processing (5)
  • eternaleconomy-core/build.gradle.kts (1 hunks)
  • eternaleconomy-core/src/jmh/java/com/eternalcode/economy/account/AccountBenchmark.java (3 hunks)
  • eternaleconomy-core/src/jmh/java/com/eternalcode/economy/leaderboard/LeaderboardServiceBenchmark.java (1 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/account/AccountManager.java (5 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardService.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • eternaleconomy-core/src/jmh/java/com/eternalcode/economy/account/AccountBenchmark.java
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardService.java
  • eternaleconomy-core/build.gradle.kts
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (5)
eternaleconomy-core/src/jmh/java/com/eternalcode/economy/leaderboard/LeaderboardServiceBenchmark.java (2)

24-33: Consider adjusting benchmark parameters for more realistic testing.

The current setup with 10 iterations might not give stable results. Also, 2M accounts might not represent real-world data size.

Would you like me to suggest more appropriate benchmark parameters based on your actual production data size?


1-82: Address database indexing concerns.

Based on Rollczi's comments, this benchmark might not accurately represent real-world performance since it uses in-memory storage instead of testing actual database indexing.

Would you like me to help create additional benchmarks that test with your actual database implementation?

eternaleconomy-core/src/main/java/com/eternalcode/economy/account/AccountManager.java (3)

19-22: Consider making the balance tracking thread-safe

The accountsByBalance map might have issues if multiple threads access it at once. Using concurrent collections would help prevent problems.


37-38: Initialization looks good!

The balance tracking is properly set up during account creation.


96-116: Clean implementation of account updates!

The save and remove methods handle all collections properly and keep everything in sync.

Copy link
Member

@Rollczi Rollczi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

czekam na zmiany związane z indeksami w AccountManager (index ma być w filed

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardService.java (1)

21-53: Handle ties carefully.

This approach might cut off accounts that share the same balance near the page boundary. Consider grouping by balance first and then slicing to avoid confusion for accounts tied on the same balance.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3e5b9c5 and f68a8d7.

📒 Files selected for processing (2)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/account/AccountManager.java (4 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardService.java (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardService.java (1)
Learnt from: vLuckyyy
PR: EternalCodeTeam/EternalEconomy#67
File: eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardService.java:1-1
Timestamp: 2025-02-04T20:41:28.072Z
Learning: In leaderboard implementations, when grouping by balance, apply size limits after grouping to avoid unfairly clipping accounts with the same balance. PriorityQueue should be avoided in streams as it doesn't guarantee ordered traversal - use simple sorting instead.
🔇 Additional comments (4)
eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardService.java (1)

55-66: Ensure concurrency safety.

These operations rely on data from AccountManager, which might change in parallel. Check if AccountManager is thread-safe or if you should lock the data structures before iterating.

eternaleconomy-core/src/main/java/com/eternalcode/economy/account/AccountManager.java (3)

90-102: Check existing accounts.

You're correctly preventing duplicates, but ensure that both name and UUID checks stay in sync so there’s no partial mismatch (e.g., same name but different UUID).


104-118: Good call removing the old account first.

This method neatly handles balance changes by removing the old record. Looks clear and straightforward!


138-148: Validate usage of these new getters.

Your new getters (getAccountsByBalance, getAccountsByBalanceSet, and getAccountsCount) expose internal data structures. Verify that consumers handle any potential mutation or concurrency concerns properly.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
eternaleconomy-core/src/jmh/java/com/eternalcode/economy/leaderboard/LeaderboardServiceBenchmark.java (1)

77-82: Consider adding edge case tests

Your benchmark checks normal cases but doesn't test edge cases like looking up users with very low balances.

Try adding a test for the worst-case scenario:

@Benchmark
public void benchmarkGetLeaderboardPosition(Blackhole blackhole) {
    Account target = targetAccounts.get(ThreadLocalRandom.current().nextInt(targetAccounts.size()));
    CompletableFuture<LeaderboardEntry> future = leaderboardService.getLeaderboardPosition(target);
    blackhole.consume(future.join());
}

+@Benchmark
+public void benchmarkGetLeaderboardPositionWorstCase(Blackhole blackhole) {
+    // Get the account with the lowest balance
+    Account target = targetAccounts.get(2);  // Using the lowest balance account from setup
+    CompletableFuture<LeaderboardEntry> future = leaderboardService.getLeaderboardPosition(target);
+    blackhole.consume(future.join());
+}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f68a8d7 and 135de45.

📒 Files selected for processing (1)
  • eternaleconomy-core/src/jmh/java/com/eternalcode/economy/leaderboard/LeaderboardServiceBenchmark.java (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
eternaleconomy-core/src/jmh/java/com/eternalcode/economy/leaderboard/LeaderboardServiceBenchmark.java (1)
Learnt from: vLuckyyy
PR: EternalCodeTeam/EternalEconomy#67
File: eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardService.java:1-1
Timestamp: 2025-02-04T20:41:28.072Z
Learning: In leaderboard implementations, when grouping by balance, apply size limits after grouping to avoid unfairly clipping accounts with the same balance. PriorityQueue should be avoided in streams as it doesn't guarantee ordered traversal - use simple sorting instead.
🔇 Additional comments (4)
eternaleconomy-core/src/jmh/java/com/eternalcode/economy/leaderboard/LeaderboardServiceBenchmark.java (4)

29-34: Good job with the benchmark setup!

The warmup iterations and configuration look right for getting reliable results.


40-41: Nice range of test data!

Testing with different account counts (100k, 1M, 2M) will help you understand how well this scales.


53-59: Smart choice using Pareto distribution

Using a Pareto distribution for balances makes your benchmark more realistic since it matches real-world wealth distribution patterns.


70-75: Benchmark looks good but needs concurrent testing

The benchmark tests page retrieval correctly but doesn't check how it performs when multiple users access it at once.

Consider adding a test for concurrent access:

@Benchmark
public void benchmarkGetLeaderboardPage(Blackhole blackhole) {
    int randomPage = ThreadLocalRandom.current().nextInt(1, MAX_PAGES + 1);
    CompletableFuture<LeaderboardPage> future = leaderboardService.getLeaderboardPage(randomPage, PAGE_SIZE);
    blackhole.consume(future.join());
}

+@Benchmark
+@Threads(8)
+public void benchmarkGetLeaderboardPageConcurrent(Blackhole blackhole) {
+    int randomPage = ThreadLocalRandom.current().nextInt(1, MAX_PAGES + 1);
+    CompletableFuture<LeaderboardPage> future = leaderboardService.getLeaderboardPage(randomPage, PAGE_SIZE);
+    blackhole.consume(future.join());
+}

@vLuckyyy vLuckyyy requested a review from Rollczi March 6, 2025 22:21
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (4)
eternaleconomy-core/src/jmh/java/com/eternalcode/economy/SchedulerImpl.java (2)

11-11: Consider making thread pool size configurable.

Using a fixed size of 1 thread could limit performance under high load. Consider making this configurable or using a cached thread pool.


47-55: Identical implementations for complete and completeAsync.

Both methods use CompletableFuture.supplyAsync which uses the common ForkJoinPool. Consider using different thread pools for sync vs async operations.

eternaleconomy-core/src/main/java/com/eternalcode/economy/account/AccountManager.java (2)

28-35: In-memory indexing might be unnecessary

Databases usually handle indexing well. Relying on an in-memory approach can be costly and complex. You could simplify by letting the database do most of this work, then retrieving results as needed.


78-80: Double-check initial balance

Starting everyone at zero might be fine, but confirm if this aligns with your economy’s needs. Ensure there's no need for a custom default balance.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 065fa1d and dab79ec.

📒 Files selected for processing (8)
  • eternaleconomy-core/src/jmh/java/com/eternalcode/economy/SchedulerImpl.java (1 hunks)
  • eternaleconomy-core/src/jmh/java/com/eternalcode/economy/account/AccountBenchmark.java (4 hunks)
  • eternaleconomy-core/src/jmh/java/com/eternalcode/economy/leaderboard/LeaderboardServiceBenchmark.java (1 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/EconomyBukkitPlugin.java (4 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/account/Account.java (1 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/account/AccountManager.java (3 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/account/AccountPaymentService.java (1 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardService.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/EconomyBukkitPlugin.java
  • eternaleconomy-core/src/jmh/java/com/eternalcode/economy/leaderboard/LeaderboardServiceBenchmark.java
  • eternaleconomy-core/src/jmh/java/com/eternalcode/economy/account/AccountBenchmark.java
🧰 Additional context used
🧠 Learnings (1)
eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardService.java (1)
Learnt from: vLuckyyy
PR: EternalCodeTeam/EternalEconomy#67
File: eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardService.java:1-1
Timestamp: 2025-03-15T13:04:40.963Z
Learning: In leaderboard implementations, when grouping by balance, apply size limits after grouping to avoid unfairly clipping accounts with the same balance. PriorityQueue should be avoided in streams as it doesn't guarantee ordered traversal - use simple sorting instead.
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (8)
eternaleconomy-core/src/main/java/com/eternalcode/economy/account/Account.java (2)

9-11: Good immutable approach for balance updates!

The new method creates a fresh Account instance with an updated balance while preserving the original UUID and name. This immutable approach prevents unexpected side effects.


13-15: Nice functional approach for balance modifications!

This method enables applying operations like add/subtract directly to the balance through a function, making the code more readable and maintainable.

eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardService.java (1)

6-12: Clean and focused interface design!

This interface follows good design principles by defining only what's needed for leaderboard functionality. The asynchronous CompletableFuture return types are appropriate for potentially time-consuming operations.

eternaleconomy-core/src/main/java/com/eternalcode/economy/account/AccountPaymentService.java (4)

19-20: Good use of functional balance updates!

The payment method now uses the new withBalance method with lambda expressions, making the code more concise and readable.


24-24: Simplified balance setting logic!

Using the withBalance method directly improves code clarity.


28-28: Consistent use of functional approach!

The addBalance method follows the same pattern, maintaining consistency throughout the service.


32-32: Consistent implementation!

The removeBalance method also uses the same functional approach.

eternaleconomy-core/src/main/java/com/eternalcode/economy/account/AccountManager.java (1)

8-9: Still not thread-safe

These collections might be used across multiple threads, posing potential data corruption issues. A past review already flagged this concern. Consider concurrent structures or proper synchronization for safety.

Also applies to: 83-97, 109-121, 123-155

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
eternaleconomy-core/src/jmh/java/com/eternalcode/economy/SchedulerImpl.java (2)

11-11: Consider allowing more concurrency.

Using a single-thread pool might limit performance for tasks expected to run in parallel.


48-55: complete and completeAsync do the same thing.

If they're meant to differ, consider using different executors or logic.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dab79ec and 523ae08.

📒 Files selected for processing (1)
  • eternaleconomy-core/src/jmh/java/com/eternalcode/economy/SchedulerImpl.java (1 hunks)
🔇 Additional comments (5)
eternaleconomy-core/src/jmh/java/com/eternalcode/economy/SchedulerImpl.java (5)

19-20: No difference between run and runAsync.

This reintroduces the earlier issue where sync and async methods are identical.


30-32: No difference between runLater and runLaterAsync.

This is the same concern noted before: both implementations do the same thing.


42-44: No difference between timer and timerAsync.

We still see the same approach for both sync and async scheduling.


75-77: Method isAsync always returns false.

This repeats the earlier pattern where async tasks aren't really tracked as async.


85-87: Method isRepeating always returns false.

This mirrors the previous comment that repeating tasks lack a proper flag.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
eternaleconomy-core/src/main/java/com/eternalcode/economy/account/AccountManager.java (1)

118-150: Simplify leaderboard page calculation.

The page calculation logic is quite complex. Consider using a simpler approach by converting accountsByBalanceSet to a list once and then applying skip/limit operations.

 @Override
 public CompletableFuture<LeaderboardPage> getLeaderboardPage(int page, int pageSize) {
     return scheduler.completeAsync(() -> {
-        List<LeaderboardEntry> list = new ArrayList<>();
-
         int totalEntries = accountsByBalance.size();
         int maxPages = (int) Math.ceil((double) totalEntries / pageSize);
         int nextPage = page + 1 < maxPages ? page + 1 : -1;
-
-        int count = 0;
-        int toSkip = page * pageSize;
-        for (Collection<Account> accounts : accountsByBalance.asMap().values()) {
-            if (count + accounts.size() < toSkip) {
-                count += accounts.size();
-                continue;
-            }
-
-            for (Account account : accounts) {
-                if (list.size() >= pageSize) {
-                    return new LeaderboardPage(list, page, maxPages, nextPage);
-                }
-
-                if (count++ < toSkip) {
-                    continue;
-                }
-
-                list.add(new LeaderboardEntry(account, count));
-            }
-        }
-
-        return new LeaderboardPage(list, page, maxPages, nextPage);
+        
+        List<Account> allAccounts = new ArrayList<>(accountsByBalanceSet);
+        int toSkip = page * pageSize;
+        
+        List<LeaderboardEntry> entries = new ArrayList<>();
+        for (int i = 0; i < pageSize && toSkip + i < allAccounts.size(); i++) {
+            Account account = allAccounts.get(toSkip + i);
+            entries.add(new LeaderboardEntry(account, toSkip + i + 1));
+        }
+        
+        return new LeaderboardPage(entries, page, maxPages, nextPage);
     });
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 523ae08 and 588160d.

📒 Files selected for processing (9)
  • eternaleconomy-core/build.gradle.kts (2 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/EconomyBukkitPlugin.java (5 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/account/Account.java (1 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/account/AccountManager.java (3 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/command/message/InvalidBigDecimalMessage.java (2 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/config/implementation/PluginConfig.java (1 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/config/implementation/messages/MessageConfig.java (1 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/config/implementation/messages/MessagesPlayerSubSection.java (2 hunks)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardCommand.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/EconomyBukkitPlugin.java
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/leaderboard/LeaderboardCommand.java
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/config/implementation/PluginConfig.java
  • eternaleconomy-core/build.gradle.kts
  • eternaleconomy-core/src/main/java/com/eternalcode/economy/config/implementation/messages/MessagesPlayerSubSection.java
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (13)
eternaleconomy-core/src/main/java/com/eternalcode/economy/command/message/InvalidBigDecimalMessage.java (1)

24-24: Good message improvement!

You've updated the error message to be more specific about requiring a positive number, which should help users better understand the issue.

eternaleconomy-core/src/main/java/com/eternalcode/economy/config/implementation/messages/MessageConfig.java (1)

9-10: Nice error message enhancement

Replacing the generic invalid amount message with this more specific one about requiring positive numbers makes the error feedback clearer for users.

eternaleconomy-core/src/main/java/com/eternalcode/economy/account/Account.java (3)

4-6: Good job adding the necessary imports.

These imports support the new functionality in the class.


10-16: Nice addition of convenience methods for balance updates.

These methods make it easier to create new Account instances with updated balances, following good immutable object practices.


18-28: Be careful with equals/hashCode implementation.

The equals and hashCode methods only consider uuid and name, but not balance. This means two accounts with the same uuid and name but different balances will be considered equal.

This might be intentional for your use case (comparing accounts regardless of balance), but could cause unexpected behavior in collections.

eternaleconomy-core/src/main/java/com/eternalcode/economy/account/AccountManager.java (8)

3-22: Good addition of imports for new functionality.

The imports support the leaderboard implementation.


23-23: Nice implementation of the LeaderboardService interface.

This follows good design by making the AccountManager implement a clear interface for leaderboard operations.


28-35: Consider thread safety for collections.

The TreeMultimap and TreeMultiset are not thread-safe. If this class is accessed from multiple threads, consider using concurrent collections or synchronization.


38-43: Good addition of scheduler dependency.

Adding the scheduler as a dependency allows for async operations in the leaderboard methods.


45-55: Updated factory method with scheduler parameter.

The static create method now accepts the scheduler parameter needed for leaderboard operations.


78-81: Simplified account creation approach.

The code now creates an account with zero balance and uses the save method to store it.


83-98: Improved save method with proper collection updates.

The save method now correctly handles removing old account entries from collections before adding the new ones. This prevents inconsistencies in the data structures.


110-117: Good implementation of getLeaderboardPosition.

Using BoundType.CLOSED ensures the target account is included when counting positions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🆕 feature New feature or request ✅ needs testing Issue needs verification.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

/baltop
7 participants