Skip to content

Version 1.0: Initial Release - #1

Open
benrobson wants to merge 28 commits into
masterfrom
staging
Open

Version 1.0: Initial Release#1
benrobson wants to merge 28 commits into
masterfrom
staging

Conversation

@benrobson

@benrobson benrobson commented Jan 4, 2025

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a comprehensive vault challenge system for Minecraft
    • Added interactive block submission and tracking mechanics
    • Implemented a points-based leaderboard system
  • Commands

    • Added new commands for vault management:
      • /bvstart: Begin the vault challenge
      • /bvsubmit: Submit items to the vault
      • /bvprogress: Check vault progress
      • /bvleaderboard: View top contributors
  • Documentation

    • Updated README with detailed plugin features and functionality
    • Enhanced configuration options for vault settings
  • Chores

    • Updated project dependencies and build configuration
    • Restructured project file organization

@coderabbitai

coderabbitai Bot commented Jan 4, 2025

Copy link
Copy Markdown

Walkthrough

The pull request introduces a comprehensive implementation of the BlockVault Minecraft plugin, focusing on creating an interactive museum-like challenge where players can contribute and track their progress. The changes include setting up the project structure, implementing core functionality through utility classes, adding command handlers for various interactions, and configuring the plugin's behavior through configuration files. The plugin enables players to start a vault challenge, submit items, check progress, and view a leaderboard.

Changes

File/Directory Change Summary
.gitignore Added target to ignored files/directories
README.md Expanded documentation with detailed plugin features, interaction modes, points system, and command descriptions
dependency-reduced-pom.xml New file defining Maven project configuration with dependencies and build settings
pom.xml Added enginehub-maven repository and worldedit-bukkit dependency
src/main/java/me/benrobson/blockvault/ Replaced Blockvault.java with BlockVault.java and added multiple command and utility classes
src/main/resources/config.yml New configuration file with vault settings, timer, points system, and language configurations
src/main/resources/plugin.yml Updated plugin name, main class, and added command entries

Sequence Diagram

sequenceDiagram
    participant Player
    participant BlockVault Plugin
    participant VaultUtil
    participant FileUtil

    Player->>BlockVault Plugin: /bvstart
    BlockVault Plugin->>VaultUtil: Check vault status
    BlockVault Plugin->>FileUtil: Update configuration
    BlockVault Plugin-->>Player: Vault challenge started

    Player->>BlockVault Plugin: /bvsubmit
    BlockVault Plugin->>VaultUtil: Validate item
    BlockVault Plugin->>FileUtil: Save player progress
    BlockVault Plugin-->>Player: Item submitted successfully

    Player->>BlockVault Plugin: /bvleaderboard
    BlockVault Plugin->>VaultUtil: Retrieve player points
    BlockVault Plugin-->>Player: Display top contributors
Loading

Poem

🐰 In the vault of blocks so bright,
Where pixels dance with pure delight,
Collect and score, climb the height,
A rabbit's challenge, pure and tight!
BlockVault awaits, come join the fight! 🏆


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ 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. (Beta)
  • @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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🔭 Outside diff range comments (1)
pom.xml (1)

Line range hint 31-37: Enhance shade plugin configuration

The shade plugin configuration should include minimization and relocation rules to reduce the final JAR size and avoid potential conflicts.

Add the following configuration:

   <plugin>
     <groupId>org.apache.maven.plugins</groupId>
     <artifactId>maven-shade-plugin</artifactId>
     <version>3.5.3</version>
     <executions>
       <execution>
         <phase>package</phase>
         <goals>
           <goal>shade</goal>
         </goals>
+        <configuration>
+          <minimizeJar>true</minimizeJar>
+          <filters>
+            <filter>
+              <artifact>*:*</artifact>
+              <excludes>
+                <exclude>META-INF/*.SF</exclude>
+                <exclude>META-INF/*.DSA</exclude>
+                <exclude>META-INF/*.RSA</exclude>
+              </excludes>
+            </filter>
+          </filters>
+          <relocations>
+            <!-- Add relocations if you shade any libraries -->
+          </relocations>
+        </configuration>
       </execution>
     </executions>
   </plugin>
🧹 Nitpick comments (17)
src/main/java/me/benrobson/blockvault/util/VaultUtil.java (3)

35-68: Optimize material filtering logic.
Right now, it iterates over Material.values(), which can be large, and checks material.isBlock() || material.isItem(). This is fine for smaller plugins, but consider caching or maintaining a refined material list if you anticipate frequent calls or a large environment. Also, note that .toLowerCase() usage for excluded items implies the config’s excluded items must be strictly lowercase.


70-83: Potential performance gain by reusing string builder.
The formatMaterialName method is solid. As a minor optimization, splitting and capitalizing each part could be done with a single pass, but the current approach is clear and perfectly acceptable for typical usage.


86-113: Consider using a Set for faster lookups in isItemAdded().
Checking each player’s list requires a nested loop. For large numbers of players/items, performance may be impacted. One approach is to store all collected items in a HashSet (or multiple sets by player) to allow faster membership tests.

src/main/java/me/benrobson/blockvault/commands/bvupdatestate.java (1)

17-17: Class naming convention.
By convention, Java class names start with an uppercase letter. Consider renaming bvupdatestate to BvUpdateState for clarity and consistency.

src/main/java/me/benrobson/blockvault/commands/bvstart.java (1)

11-11: Class naming style.
Similarly to bvupdatestate, rename bvstart to follow Java naming conventions (e.g., BvStart). This improves readability and consistency with other classes.

src/main/java/me/benrobson/blockvault/util/FileUtil.java (2)

30-64: Maintain synchronization between in-memory and plugin config.
Calling both saveConfig() and plugin.reloadConfig() is usually fine. However, the plugin’s default getConfig() can diverge from your YamlConfiguration instance if updates happen outside your FileUtil class. Consider consistently funneling all reads/writes through FileUtil to prevent confusion.


58-65: Offer fallback if reload fails.
If reloadConfig() fails or the file is corrupted, the code might proceed with partial data. Consider a fallback strategy (e.g., revert to a known good backup) or more robust error handling to keep the plugin stable.

src/main/java/me/benrobson/blockvault/commands/bvprogress.java (1)

30-33: Check for 'items' configuration section to avoid NullPointerException
If "vault_items.yml" does not contain the "items" section, vaultItems.getConfigurationSection("items") could return null, potentially causing a NullPointerException. It might be wise to verify that the section exists before calling getKeys(false).

 File vaultItemsFile = new File(plugin.getDataFolder(), "vault_items.yml");
 YamlConfiguration vaultItems = YamlConfiguration.loadConfiguration(vaultItemsFile);
 
+if (vaultItems.getConfigurationSection("items") == null) {
+    sender.sendMessage("§cNo items defined in vault_items.yml. Please contact an admin.");
+    return true;
+}
 
 int totalItems = vaultItems.getConfigurationSection("items").getKeys(false).size();
src/main/java/me/benrobson/blockvault/commands/bvleaderboard.java (2)

39-43: Suggest verifying that relevant data exists
If "vault_data" is missing or empty, you correctly show an error message. You might also consider logging a warning on the server side so that admins know the data is missing.


46-54: Avoid potential concurrency issues
Although unlikely in a typical Minecraft scenario, reading and updating vault_data.yml in different threads could lead to stale or incomplete data. Ensure that any concurrent writes are synchronized or queued on the main thread.

src/main/java/me/benrobson/blockvault/commands/bvsubmit.java (2)

30-35: Enhance feedback for non-player command senders
You return early if the sender isn't a player, which is good. For clarity, you might also consider providing a usage message or a link to documentation for non-player contexts.


79-82: Notify admins or log if an item is missing from 'vault_items.yml'
The code assigns the "COMMON" category by default if the item isn't found in vault_items.yml, but you may want to log a warning to let admins or developers know that the item is missing, to prevent silent misconfigurations.

String category = vaultItems.getString("items." + itemName, "COMMON"); // Default to COMMON
int pointsPerCategory = config.getInt("points." + category, 1); // Default to 1 point

+if (!vaultItems.contains("items." + itemName)) {
+    plugin.getLogger().warning("Item '" + itemName + "' not found in vault_items.yml. Defaulting to 'COMMON'.");
+}
src/main/java/me/benrobson/blockvault/BlockVault.java (2)

26-30: Refactor command registration for better maintainability

Consider creating a command registry utility to reduce repetition and improve maintainability. This would also make it easier to add new commands in the future.

+    private void registerCommands() {
+        Map<String, CommandExecutor> commands = Map.of(
+            "bvstart", new bvstart(this),
+            "bvsubmit", new bvsubmit(this),
+            "bvprogress", new bvprogress(this),
+            "bvleaderboard", new bvleaderboard(this),
+            "bvupdatestate", new bvupdatestate(this)
+        );
+        
+        commands.forEach((name, executor) -> 
+            getCommand(name).setExecutor(executor));
+    }

34-36: Add logging for critical operations

Important operations like config saving and vault item generation should be logged for better debugging and monitoring.

+        getLogger().info("Saving default configuration...");
         saveDefaultConfig();
+        getLogger().info("Generating vault items...");
         VaultUtil.generateVaultItems(this);
+        getLogger().info("Scheduling vault state task...");
         scheduleVaultStateTask(this, vaultUtil, fileUtil);
README.md (1)

28-32: Enhance command documentation

The commands section should include:

  • All required and optional permissions
  • Command usage examples
  • Command arguments and their descriptions

Consider adding a more detailed command section like this:

## Commands

| Command | Description | Permission | Usage Example |
|---------|-------------|------------|---------------|
| `/bvstart` | Starts the vault challenge | `blockvault.start` | `/bvstart` |
| `/bvsubmit` | Submit items to the vault | `blockvault.submit` | `/bvsubmit` |
| `/bvprogress` | View vault progress | `blockvault.progress` | `/bvprogress` |
| `/bvleaderboard` | View top contributors | `blockvault.leaderboard` | `/bvleaderboard` |
src/main/resources/config.yml (2)

17-115: Organize excluded items by categories

The excluded items list is quite long and could be better organized using YAML anchors and aliases. Group items by type (e.g., spawn eggs, technical blocks, etc.).

  excludeditems:
-    - debug_stick
-    - structure_block
-    # ... many more items ...
+    technical_blocks: &technical
+      - debug_stick
+      - structure_block
+      - barrier
+      - command_block
+      - chain_command_block
+      - repeating_command_block
+    
+    special_blocks: &special
+      - spawner
+      - end_portal_frame
+      - bedrock
+      - dragon_egg
+    
+    spawn_eggs: &spawn_eggs
+      - piglin_brute_spawn_egg
+      - parrot_spawn_egg
+      # ... other spawn eggs ...
+    
+    excludeditems:
+      - *technical
+      - *special
+      - *spawn_eggs

128-128: Add newline at end of file

Add a newline character at the end of the file to comply with YAML standards.

  prefix: "&8&l[&3BD&8&l]"
+
🧰 Tools
🪛 yamllint (1.35.1)

[error] 128-128: no new line character at the end of file

(new-line-at-end-of-file)

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 7e213e4 and 8293cba.

📒 Files selected for processing (16)
  • .gitignore (1 hunks)
  • README.md (1 hunks)
  • dependency-reduced-pom.xml (1 hunks)
  • pom.xml (2 hunks)
  • src/main/java/me/benrobson/blockvault/BlockVault.java (1 hunks)
  • src/main/java/me/benrobson/blockvault/Blockvault.java (0 hunks)
  • src/main/java/me/benrobson/blockvault/commands/bvleaderboard.java (1 hunks)
  • src/main/java/me/benrobson/blockvault/commands/bvprogress.java (1 hunks)
  • src/main/java/me/benrobson/blockvault/commands/bvstart.java (1 hunks)
  • src/main/java/me/benrobson/blockvault/commands/bvsubmit.java (1 hunks)
  • src/main/java/me/benrobson/blockvault/commands/bvupdatestate.java (1 hunks)
  • src/main/java/me/benrobson/blockvault/util/FileUtil.java (1 hunks)
  • src/main/java/me/benrobson/blockvault/util/ScheduleUtil.java (1 hunks)
  • src/main/java/me/benrobson/blockvault/util/VaultUtil.java (1 hunks)
  • src/main/resources/config.yml (1 hunks)
  • src/main/resources/plugin.yml (1 hunks)
💤 Files with no reviewable changes (1)
  • src/main/java/me/benrobson/blockvault/Blockvault.java
✅ Files skipped from review due to trivial changes (1)
  • .gitignore
🧰 Additional context used
🪛 yamllint (1.35.1)
src/main/resources/config.yml

[error] 128-128: no new line character at the end of file

(new-line-at-end-of-file)

🔇 Additional comments (10)
pom.xml (1)

75-80: Verify WorldEdit version compatibility

The WorldEdit dependency version 7.2.9 should be verified for compatibility with Paper 1.21.3. Additionally, consider adding version properties for better version management.

+  <properties>
+    <!-- Existing properties -->
+    <worldedit.version>7.2.9</worldedit.version>
+  </properties>

   <dependency>
     <groupId>com.sk89q.worldedit</groupId>
     <artifactId>worldedit-bukkit</artifactId>
-    <version>7.2.9</version>
+    <version>${worldedit.version}</version>
     <scope>provided</scope>
   </dependency>

Let's verify the compatibility:

src/main/java/me/benrobson/blockvault/util/VaultUtil.java (2)

21-29: Ensure FileUtil dependency is used consistently.
The constructor correctly initializes the fileUtil dependency, but watch out for any future method calls that also rely on this utility class. Make sure they consistently use the fileUtil instance rather than creating a new one on the fly to avoid sync issues or unexpected configuration states.


31-33: Validate config loading for hasStarted().
The method returns a boolean from the plugin’s config. Ensure you reload or save config if there's any chance the file changed at runtime before reading vault.started.

src/main/java/me/benrobson/blockvault/util/ScheduleUtil.java (2)

17-28: Schedule task usage confirmed.
Using Bukkit.getScheduler().runTaskTimer with the correct interval in ticks is a standard way to schedule recurring tasks. This design is straightforward and avoids concurrency pitfalls.


17-28: Gracefully handle negative or zero intervals.
If intervalMinutes is zero or negative, the scheduled task could cause a flood of repeated calls or never run at all. Consider adding a check that logs an error or defaults to a minimum safe interval (e.g., 1 minute).

src/main/java/me/benrobson/blockvault/commands/bvupdatestate.java (1)

28-44: Restrict command usage to correct context.
You’ve already enforced player-only usage plus permission checks. This is good. Optionally, add a help message or usage instructions for players who type the command incorrectly or with extra arguments.

src/main/java/me/benrobson/blockvault/commands/bvstart.java (1)

22-49: Ensure consistent state updates.
Starting the vault updates vault.started to true and logs the start time in config. Confirm that any commands checking the vault state re-read the config so they don’t rely on stale data. Your usage of fileUtil.updateConfigValue helps, but verifying no concurrency or ordering issues might be beneficial.

src/main/resources/plugin.yml (2)

1-3: Updated plugin name and main class
Renaming the plugin to “BlockVault” and referencing BlockVault instead of Blockvault is a good improvement for clarity. No issues found here.


5-20: Commands properly registered
All the new commands (bvsubmit, bvleaderboard, bvprogress, bvstart, bvupdatestate) appear to be mapped correctly with usage instructions. This is essential for discoverability and user guidance.

src/main/resources/config.yml (1)

9-16: Validate region coordinates

The region coordinates should be validated to ensure:

  1. Upper region Y is always higher than lower region Y
  2. Coordinates form a valid 3D space

Let's check if there's validation logic in the codebase:

Comment thread dependency-reduced-pom.xml Outdated
Comment on lines +1 to +71
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>me.benrobson</groupId>
<artifactId>blockvault</artifactId>
<name>blockvault</name>
<version>1.0.0</version>
<build>
<defaultGoal>clean package</defaultGoal>
<resources>
<resource>
<filtering>true</filtering>
<directory>src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>papermc-repo</id>
<url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
<repository>
<id>sonatype</id>
<url>https://oss.sonatype.org/content/groups/public/</url>
</repository>
<repository>
<id>enginehub-maven</id>
<url>https://maven.enginehub.org/repo/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
<version>1.21.3-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.sk89q.worldedit</groupId>
<artifactId>worldedit-bukkit</artifactId>
<version>7.2.9</version>
<scope>provided</scope>
</dependency>
</dependencies>
<properties>
<java.version>21</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove dependency-reduced-pom.xml from version control

This file is automatically generated by the maven-shade-plugin during the build process and should not be committed to version control. Add it to .gitignore to prevent accidental commits.

Create or update .gitignore:

+dependency-reduced-pom.xml
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>me.benrobson</groupId>
<artifactId>blockvault</artifactId>
<name>blockvault</name>
<version>1.0.0</version>
<build>
<defaultGoal>clean package</defaultGoal>
<resources>
<resource>
<filtering>true</filtering>
<directory>src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>papermc-repo</id>
<url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
<repository>
<id>sonatype</id>
<url>https://oss.sonatype.org/content/groups/public/</url>
</repository>
<repository>
<id>enginehub-maven</id>
<url>https://maven.enginehub.org/repo/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
<version>1.21.3-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.sk89q.worldedit</groupId>
<artifactId>worldedit-bukkit</artifactId>
<version>7.2.9</version>
<scope>provided</scope>
</dependency>
</dependencies>
<properties>
<java.version>21</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
dependency-reduced-pom.xml

Comment on lines +115 to +190
public void updateVaultState(Player player) {
try {
// Parse region coordinates from config
int upperX = fileUtil.getConfig().getInt("vault.region.upperregion.X");
int upperY = fileUtil.getConfig().getInt("vault.region.upperregion.Y");
int upperZ = fileUtil.getConfig().getInt("vault.region.upperregion.Z");

int lowerX = fileUtil.getConfig().getInt("vault.region.lowerregion.X");
int lowerY = fileUtil.getConfig().getInt("vault.region.lowerregion.Y");
int lowerZ = fileUtil.getConfig().getInt("vault.region.lowerregion.Z");

World world = Bukkit.getWorlds().get(0);
if (world == null) {
String errorMsg = "§cWorld not found! Stopping the update process.";
Bukkit.getLogger().warning(errorMsg);
if (player != null) player.sendMessage(errorMsg);
return;
}

// Normalize coordinates
int minX = Math.min(upperX, lowerX);
int maxX = Math.max(upperX, lowerX);
int minY = Math.min(upperY, lowerY);
int maxY = Math.max(upperY, lowerY);
int minZ = Math.min(upperZ, lowerZ);
int maxZ = Math.max(upperZ, lowerZ);

int foundCount = 0;
int updatedCount = 0;

// Iterate over entities in the specified region
for (Entity entity : world.getEntities()) {
if (entity instanceof ItemFrame) {
Location loc = entity.getLocation();
if (loc.getX() >= minX && loc.getX() <= maxX &&
loc.getY() >= minY && loc.getY() <= maxY &&
loc.getZ() >= minZ && loc.getZ() <= maxZ) {

ItemFrame itemFrame = (ItemFrame) entity;
if (itemFrame.getItem() != null && itemFrame.getItem().getType() != Material.AIR) {
String itemName = itemFrame.getItem().getType().toString().toLowerCase();

boolean isInVault = isItemAdded(itemName);
String frameMessage = String.format("§aItemFrame at [%d, %d, %d] has item: %s (In Vault: %s).",
loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), itemName, isInVault ? "Yes" : "No");
Bukkit.getLogger().info(frameMessage);
if (player != null) player.sendMessage(frameMessage);

// Get the block behind the item frame
Location blockBehindLoc = itemFrame.getLocation().getBlock().getRelative(itemFrame.getAttachedFace()).getLocation();
Material newMaterial = isInVault ? Material.LIME_STAINED_GLASS : Material.RED_STAINED_GLASS;
blockBehindLoc.getBlock().setType(newMaterial);

String updateMessage = String.format("§eBlock behind ItemFrame at [%d, %d, %d] replaced with %s.",
loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), newMaterial.name());
Bukkit.getLogger().info(updateMessage);
if (player != null) player.sendMessage(updateMessage);

foundCount++;
updatedCount++;
}
}
}
}

String summaryMessage = String.format("§aFound %d item frames and updated %d blocks in the specified region.",
foundCount, updatedCount);
Bukkit.getLogger().info(summaryMessage);
if (player != null) player.sendMessage(summaryMessage);
} catch (Exception e) {
String errorMessage = "§cAn error occurred while processing the region.";
Bukkit.getLogger().severe(errorMessage);
e.printStackTrace();
if (player != null) player.sendMessage(errorMessage);
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid scanning all world entities for region checks.
Calling world.getEntities() can be expensive on large servers, as it returns every entity in every chunk. If possible, use region-specific queries (e.g., World#getNearbyEntities or chunk-based iteration) to limit the cost.

Comment on lines +192 to +230
/**
* Calculates the collective progress of all players in the vault and generates a progress bar.
*
* @param vaultData The YamlConfiguration object for vault data.
* @param totalItems The total number of items required for the vault.
* @return A formatted progress string showing the collective percentage and progress bar.
*/
public String getProgress(YamlConfiguration vaultData, int totalItems) {
int totalCollectedItems = 0;

// Iterate through all player entries in the vault data to sum up collected items
for (String playerName : vaultData.getConfigurationSection("vault_data").getKeys(false)) {
List<String> playerCollectedItems = vaultData.getStringList("vault_data." + playerName + ".collected_items");
totalCollectedItems += playerCollectedItems.size();
}

// Calculate the percentage of progress for the collective effort
int progressPercentage = (int) ((double) totalCollectedItems / totalItems * 100);

// Create a progress bar
StringBuilder progressBar = new StringBuilder("§a[");
int barLength = 50; // Total bar length
int progressLength = (int) ((progressPercentage / 100.0) * barLength);

for (int i = 0; i < barLength; i++) {
if (i < progressLength) {
progressBar.append("§a|");
} else {
progressBar.append("§7|");
}
}
progressBar.append("§a]");

// Create the progress string with total collected and total required items
String progressInfo = String.format("§e%d/%d collected", totalCollectedItems, totalItems);

// Return the full progress string
return progressInfo + " §f(" + progressPercentage + "% complete)\n" + progressBar;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Handle potential zero-case total items.
If totalItems is zero or unexpectedly low, (double) totalCollectedItems / totalItems can lead to division by zero. Consider defensive checks to prevent errors or odd behavior.

Comment on lines +48 to +53
String progress = vaultUtil.getProgress(vaultData, totalItems);

// Display progress
player.sendMessage("§aVault Progress");
player.sendMessage("==================================");
player.sendMessage(progress);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codebase verification

Division by zero is possible in getProgress method
The review comment is correct. Looking at the implementation of getProgress in VaultUtil.java, there's no check for zero total items, which could lead to an ArithmeticException when calculating the progress percentage:

int progressPercentage = (int) ((double) totalCollectedItems / totalItems * 100);

The suggested fix to add a zero check in the calling code is appropriate to prevent this issue.

  • Location: src/main/java/me/benrobson/blockvault/commands/bvprogress.java
  • Location: src/main/java/me/benrobson/blockvault/util/VaultUtil.java (consider adding the zero check here as well for better encapsulation)
🔗 Analysis chain

Handle zero total items scenario
If totalItems is zero, a progress calculation might result in a division by zero or an inaccurate percentage. Add a check to handle that edge case gracefully.

String progress = vaultUtil.getProgress(vaultData, totalItems);

+if (totalItems == 0) {
+    player.sendMessage("§cNo items to track yet. Progress is undefined.");
+    return true;
+}

player.sendMessage("§aVault Progress");
player.sendMessage("==================================");
player.sendMessage(progress);

Let me verify the concern by checking the implementation of getProgress method and how it handles zero total items.


Let me check the implementation of getProgress in VaultUtil.java to understand how it handles the zero total items case.

🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Search for getProgress method implementation
ast-grep --pattern 'getProgress($_, $_) {
  $$$
}'

Length of output: 52


Script:

#!/bin/bash
# Search for any usage of getProgress method to understand the context
rg "getProgress" -A 3

Length of output: 862


Script:

#!/bin/bash
# Get the content of VaultUtil.java to examine getProgress implementation
cat src/main/java/me/benrobson/blockvault/util/VaultUtil.java

Length of output: 9936

Comment on lines +30 to +111
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
sender.sendMessage("§cOnly players can use this command!");
return true;
}

Player player = (Player) sender;

if (!vaultUtil.hasStarted()) {
sender.sendMessage("§cYou cannot submit items as the Vault has not been opened yet.");
return true;
}

ItemStack itemInHand = player.getInventory().getItemInMainHand();

if (itemInHand == null || itemInHand.getType() == Material.AIR) {
player.sendMessage("§cYou are not holding any item or block!");
return true;
}

// Get item display name or fallback to material name
ItemMeta meta = itemInHand.getItemMeta();
String displayName = (meta != null && meta.hasDisplayName()) ? meta.getDisplayName() : formatMaterialName(itemInHand.getType());
String itemName = itemInHand.getType().name().toLowerCase();

// Load configuration files
File vaultDataFile = new File(plugin.getDataFolder(), "vault_data.yml");
File vaultItemsFile = new File(plugin.getDataFolder(), "vault_items.yml");
File configFile = new File(plugin.getDataFolder(), "config.yml");

YamlConfiguration vaultData = YamlConfiguration.loadConfiguration(vaultDataFile);
YamlConfiguration vaultItems = YamlConfiguration.loadConfiguration(vaultItemsFile);
YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);

// Check if item has already been collected globally
String collector = vaultData.getString("vault_data.global_collected_items." + itemName);
if (collector != null) {
player.sendMessage("§cItem " + displayName + " has already been collected by " + collector + "!");
return true;
}

// Add item to player's collected items
List<String> playerItems = vaultData.getStringList("vault_data." + player.getName() + ".collected_items");
if (playerItems.contains(itemName)) {
player.sendMessage("§cYou have already collected " + displayName + "!");
return true;
}

// Determine the item's point category and corresponding points
String category = vaultItems.getString("items." + itemName, "COMMON"); // Default to COMMON
int pointsPerCategory = config.getInt("points." + category, 1); // Default to 1 point

playerItems.add(itemName);

vaultData.set("vault_data." + player.getName() + ".collected_items", playerItems);

// Update player points
int currentPoints = vaultData.getInt("vault_data." + player.getName() + ".points", 0);
vaultData.set("vault_data." + player.getName() + ".points", currentPoints + pointsPerCategory);

// Update global collected items
vaultData.set("vault_data.global_collected_items." + itemName, player.getName());

try {
vaultData.save(vaultDataFile);

// Remove one item from the player's hand
if (itemInHand.getAmount() > 1) {
itemInHand.setAmount(itemInHand.getAmount() - 1);
} else {
player.getInventory().setItemInMainHand(null);
}

player.sendMessage("§aSuccessfully added " + displayName + " to your vault! (§b+" + pointsPerCategory + " points§a)");
} catch (IOException e) {
player.sendMessage("§cFailed to save collected item. Please try again.");
e.printStackTrace();
}

return true;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider splitting logic into smaller methods
The command method handles multiple tasks—checking preconditions, reading config files, updating data, removing items from inventory. For readability and maintainability, consider splitting these tasks among smaller private methods (e.g., validatePreconditions(), processSubmission(), updatePlayerInventory()).


@Override
public void onEnable() {
getConsoleSender().sendMessage(getConfig().get("lang.prefix") + "§aPlugin is now enabled!");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add null check for config prefix

The getConfig().get("lang.prefix") call could return null if the prefix is not defined in config.yml. Add a null check or provide a default value.

-        getConsoleSender().sendMessage(getConfig().get("lang.prefix") + "§aPlugin is now enabled!");
+        String prefix = getConfig().getString("lang.prefix", "§8§l[§3BD§8§l]");
+        getConsoleSender().sendMessage(prefix + "§aPlugin is now enabled!");
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
getConsoleSender().sendMessage(getConfig().get("lang.prefix") + "§aPlugin is now enabled!");
String prefix = getConfig().getString("lang.prefix", "§8§l[§3BD§8§l]");
getConsoleSender().sendMessage(prefix + "§aPlugin is now enabled!");

Comment on lines +32 to +33
// Register events

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codebase verification

Event listeners are missing and need to be implemented

The review comment is correct. After examining the main plugin class and searching through the codebase, there are no event listeners implemented despite the comment indicating they should be registered. This is important because:

  • The main class BlockVault.java has a comment "Register events" but no event registration code follows
  • No event listener classes were found in the codebase (no classes implementing/extending Listener)
  • No @EventHandler annotations were found
  • The plugin seems to be a vault challenge plugin that would likely need to listen to various game events to function properly

You should:

  • Create event listener class(es) implementing org.bukkit.event.Listener
  • Implement necessary event handlers with @EventHandler annotations
  • Register the listeners using getServer().getPluginManager().registerEvents(listener, this) in the main class
🔗 Analysis chain

Implement event listeners

There's a comment indicating event listeners should be registered, but none are implemented. This could lead to missing crucial game events needed for the vault challenge.

Let's check if any event listeners are defined in the codebase:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for event listener implementations
rg -l "implements Listener|extends Listener" --type java

Length of output: 58


Script:

#!/bin/bash
# Let's try a different approach to find event-related code
# 1. Search for event handler annotations
rg "@EventHandler" --type java

# 2. Search for any files in 'events' directories
fd -t f -e java . events/

# 3. Search for event-related method names
rg "on[A-Z][a-zA-Z]+Event" --type java

Length of output: 194


Script:

#!/bin/bash
# Let's check the plugin.yml to understand the plugin structure
# and look for any event registration in the main class
cat src/main/resources/plugin.yml

# Check the main class content
cat src/main/java/me/benrobson/blockvault/BlockVault.java

Length of output: 2044

Comment thread README.md Outdated
Comment on lines +7 to +27
## Features
### Interactive Block Displays
* Sections dedicated to specific block categories (e.g., wood, ores, decorative blocks).
* Blocks and items can be placed on predefined slots with item frames or display stands, indicating where each item belongs and can be contributed to.

### Points System
* Players earn points for each block they unlock and contribute to the museum.
* The points awarded vary based on the rarity of the block/item:
* **Common Blocks:** 1 point per block.
* **Uncommon Blocks:** 5 points per block.
* **Rare Blocks/Items:** 10+ points per block.
* A running total of points is tracked for each player which can be found using `/bvleaderboard`, contributing to their leaderboard position.

### Tracking Progress
* Leaderboard displays the top contributors and their points when using `/bvleaderboard`.
* A progress bar or percentage indicator shows how close the server is to completing the collection using `/bvprogress`.

### Progress Leaderboard
* Progress can be viewed in real-time using a hologram display, showcasing the top contributors and collection milestones.
* Use the `/bvleaderboard` command to see a detailed leaderboard of top contributors, including points and blocks contributed.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add installation and configuration sections

The documentation should include setup instructions and configuration guide to help server administrators.

Consider adding these sections before the Features section:

## Installation

1. Download the latest release from [Releases]
2. Place the JAR file in your server's `plugins` folder
3. Restart your server
4. Configure the plugin in `plugins/BlockVault/config.yml`

## Configuration

The plugin can be configured through `config.yml`:

### Vault Settings
- `vault.region`: Define the physical boundaries of your vault
- `vault.excludeditems`: List of items that cannot be submitted
- `vault.updateinterval`: How often the vault state updates (in seconds)

### Points System
- Configure points for different item rarities
- Customize the scoring system for your server

@benrobson

Copy link
Copy Markdown
Collaborator Author

Awaiting for events team to test.

…plugin; enhance plugin.yml with descriptions and permissions.
…ermission checks

Enhance ScheduleUtil to improve task scheduling with configurable startup delay

Revamp VaultUtil to streamline vault state updates and remove deprecated methods

Update config.yml to reflect new database settings and remove obsolete vault settings

Add Database class for managing MySQL connections and operations with HikariCP

Implement Manifest and TargetEntry classes for structured target data management

Introduce HeadUtil for handling player head placements and profile serialization
…ion tracking and monthly leaderboard functionality
…consumption; improve error handling in database queries and display service
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant