Inventory Framework
repository·main·Indexed 41 days ago
https://github.com/devnatan/inventory-frameworkA Minecraft Inventory API framework providing a high-level, secure, and robust way to create custom inventories with specialized interaction behaviors. It includes a Minestom platform implementation featuring RenderContext for item manipulation and a ViewFrame for managing view lifecycles, as well as an IntelliJ plugin for static analysis-based visual previews of inventory layouts.
What's inside Inventory Framework
- Inventory Framework is a Minecraft Inventory API framework designed to simplify the creation of custom inventories. It provides a high-level, secure, and robust API that allows developers to implement varied interaction treatments while automatically handling and resolving known platform-specific issues internally.
How the IntelliJ Plugin preview works
mainThe IntelliJ plugin provides a split-view editor where the source code is on the left and a visual preview of the inventory view is on the right.
Key Characteristics:
- Static Analysis Only: The preview is built using PSI/UAST (static analysis). It never compiles or runs your code. Consequently, anything depending on runtime state (non-literal variables, complex logic, or lambdas) will appear as a generic placeholder.
- Live Refresh: The preview automatically re-extracts and repaints approximately 300ms after you finish an edit (debounced).
- Dumb-mode Safe: If the project is still indexing, the plugin returns no match instead of erroring, and it will automatically retry once indexing is complete.
- Editor Integration: It uses a single editor tab with a split view. You can use the standard top-right IntelliJ icons to switch between 'editor-only', 'split', or 'preview-only' modes.
Branch naming conventions
mainThe
masterbranch is the only long-term branch. For short-term work, use the following naming patterns:fix/something-needs-fix: Small routine patches for existing features.feat/something-new: New features or changes to existing features (be mindful of breaking changes).docs/improves-documentation-for-this-feature: Changes to documentation that do not impact source code.chore/update-gradle-version: Updates to project files not related to source code.
Define items in the preview using ItemExtractor
mainTo see items in the preview, you must use patterns that the static analyzer can resolve. The analyzer looks for literal
new ItemStack(Material.X)calls or simple local variable initializers.Supported Item Patterns:
- Direct Slot Assignment:
slot(index, item),slot(index).withItem(item). - Boundary Slots:
firstSlot(item),lastSlot(item). - Layout Slots:
layoutSlot(char, item). - Helper Fallbacks: If you pass a
Material.Xdirectly to a helper (e.g.,withItem(ExampleUtil.displayItem(Material.STONE, "Label"))), the plugin uses theMaterialas a best-effort guess, even though it doesn't execute the helper. - Stack Counts:
new ItemStack(Material.X, amount)renders a vanilla-style count badge ifamountis a literal or a non-reassigned local variable. - Loop Support: Inside a simple bounded loop (e.g.,
for (int i = 1; i <= 5; i++)), the plugin can resolve the loop counterito render incrementing stack counts (e.g., 1 through 5).
// Example of what the plugin can resolve slot(0, new ItemStack(Material.DIAMOND, 64)); // Example of loop-based stack counts for (int i = 1; i <= 5; i++) { render.availableSlot(new ItemStack(Material.GOLD_INGOT, i)); }- Direct Slot Assignment:
Git commit message standards
mainCommit messages should follow the seven rules of a great Git commit message to ensure clarity and maintainability:
- Separate the subject from the body with a blank line.
- Limit the subject line to 72 characters.
- Capitalize the subject line.
- Do not end the subject line with a period.
- Use the imperative mood in the subject line (e.g., "Add feature" instead of "Added feature").
- Wrap the body at 72 characters.
- Use the body to explain what and why, rather than how.
Note: Vague messages like "fix tests" or "now it's working" will not be accepted. Additionally, always rebase your code to avoid reverse merge commits.
Guidelines for writing code comments
mainComments should focus on explaining the why behind decisions rather than describing the code's structure or obvious behavior.
When to comment:
- When a decision departs from common wisdom or convention (explain the reasoning).
- When a code fragment required significant thought/research (e.g., if you spent >1 hour thinking about a fragment that took <2 minutes to write).
- When you need to preserve specific implementation properties, such as performance-sensitive code, goroutine synchronization, security primitives, or congestion control algorithms.
When NOT to comment:
- On program structures that follow established conventions.
- On pedantic explanations of behavior that are immediately obvious from the surrounding code.
- On behavior you cannot personally attest to.
Configure Minecraft icon paths in IntelliJ
mainThe plugin attempts to render real item icons by reading model geometry directly from a local Minecraft client installation. If the plugin cannot auto-detect your Minecraft directory (e.g., if you use a portable launcher or a custom installation path), you can manually configure it.
Setup: Go to Settings > Tools > Inventory Framework (
MinecraftIconSettings) to override the.minecraftdirectory path.Language requirements for contributions
mainAll contributions to the
inventory-frameworkproject MUST use the English language. This requirement applies to:- Source code
- Comments
- Documentation
- Commit messages
- Review comments
- Any other form of contribution
Initialize a ViewFrame
mainTo use the inventory framework in Minestom, you must create and register a
ViewFrame. TheViewFrameacts as the central controller for managing views and their lifecycles.- Create the frame using
ViewFrame.create(parentNode), passing in a MinestomEventNode(typically the server's main event node). - Call
.register()to initialize the framework, set up the element factory, and prepare the view pipeline.
val viewFrame = ViewFrame.create(server.eventNode).register()- Create the frame using
Known limitations of the IntelliJ Plugin preview
mainBecause the preview relies on static analysis rather than code execution, the following limitations apply:
- No Dynamic Evaluation: Non-literal titles,
renderWith/onRenderlambdas,displayIfconditions, and complex item expressions will show as generic placeholders. - Heuristic-based Row/Column Filling: Calls to
row(n),column(n),firstRow(), etc., use a "fill the whole row/column" heuristic. The plugin treats every call site as if it fills the entire row/column, which may not match runtime behavior if you intended to fill only a single slot. availableSlot()Heuristics: The position ofavailableSlot()is estimated based on the layout and previously extracted slots. It does not simulate runtime interactability or complex nested loops.resultSlot()is unsupported: Items placed viaresultSlot()will not appear in the preview.- No Interaction: The preview is read-only;
onClickandonSlotClickbehaviors are not simulated. - Language Support: Limited to Java and Kotlin via UAST.
- No Dynamic Evaluation: Non-literal titles,
Configure View properties for the preview
mainThe
ViewExtractoridentifies several configuration properties to render the preview correctly:- ViewType: Detected via
.type(ViewType.X)or theViews.rows(n)shorthand (which impliesCHEST). - Size: Detected via
.size(n)orViews.rows(n). - Title: Detected via
.title("literal string"). - Layout: Detected via the
layout(...)char grid. - Slot Geometry: The plugin understands per-type slot geometry (rows/columns/max slot count) for various container types including
CHEST,HOPPER,DROPPER,DISPENSER,FURNACE,BLAST_FURNACE,CRAFTING_TABLE,BREWING_STAND,BEACON,ANVIL,SHULKER_BOX,SMOKER,VILLAGER_TRADING, andPLAYER.
- ViewType: Detected via
Open a view to a player
mainUse the
openmethods on aViewFrameinstance to display an inventory (aView) to one or more players.- Single Player: Pass the
Viewclass and thePlayerobject. You can optionally provideinitialDatato pass state to the view upon opening. - Multiple Players: Pass a collection of
Playerobjects. These players will share the same inventory context and see the same state. - Existing Context: Use
openActiveto allow a player to join an already existing inventory context using itscontextId.
Note: Methods involving multiple players or active contexts are marked as
@Experimentaland may change in future releases.// Open a new view for a single player val contextId = viewFrame.open(MyView::class.java, player) // Open a new view for a single player with initial data viewFrame.open(MyView::class.java, player, myInitialData) // Open a new view for multiple players (Experimental) viewFrame.open(MyView::class.java, listOf(player1, player2)) // Open an existing context to a player (Experimental) viewFrame.openActive(MyView::class.java, "existing-context-id", player)- Single Player: Pass the