Files
mc-bot-town/nodejs/STORAGE_SYSTEM.md
2026-01-31 18:49:08 -05:00

29 KiB

Storage/Trade Bot System Documentation

Overview

A plugin-based storage and trading system for Minecraft bots. Any bot (ez or others) equipped with the StoragePlugin can:

  • Automatically discover and track chests in a storage area
  • Sort incoming items into shulker boxes
  • Track full inventory metadata (NBT, enchantments, durability)
  • Provide web API for inventory viewing (24/7)
  • Handle deposit/withdraw via the /trade command

Key Design Principle: The system is NOT hardcoded to any specific bot name. Any bot can be configured with the StoragePlugin via the plugin system.


Requirements

Functional Requirements

1. Chest Discovery

  • Scan all chests within configurable render distance
  • Automatically detect single vs double chests
  • Assign row/column positions for organization
  • No signs required - chests are positional

2. Storage Organization

  • Only shulker boxes stored in chests - no loose items
  • One item type per shulker - no mixing items in a shulker
  • Automatic categorization of items (minerals, food, tools, etc.)
  • Unlimited empty shulkers available from reserve

3. Trade Integration

  • Use existing /trade command for all item transfers
  • Max 12 slots per trade (server limitation)
  • Deposit flow: player trades → bot sorts → items stored
  • Withdraw flow: player requests → bot gathers → trade window

4. Database Persistence

  • SQLite database for inventory tracking
  • Database independent of bot being online
  • Web API reads directly from database (24/7 availability)

5. Permission System

  • Database-driven permissions (no file editing)
  • Roles: owner, team, readonly
  • Commands and web access limited by role

6. Web Interface

  • Simple but fully functional UI
  • Search inventory
  • View item counts and locations
  • Request withdrawals via web
  • No login required (whisper challenge for auth)

Technical Requirements

Stack

  • Node.js + mineflayer (existing infrastructure)
  • SQLite for database (via sqlite3 npm package)
  • Express for web API
  • Minecraft server: CoreJourney (existing)

Constraints

  • Plain shulker boxes only (no dyes, no NBT names)
  • Trade window max 12 slots
  • Bot location is secret (no player access to chests)
  • Web server must run 24/7 (separate from bot process)

Architecture

System Diagram

┌─────────────────────────────────────────────────────────────┐
│                        GAME LAYER                           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   ┌─────────────┐              ┌─────────────┐              │
│   │ StorageBot  │ (Optional)   │ Other Bots  │              │
│   │ (e.g., ez)  │              │             │              │
│   │ - Scan      │              │ - Proxy     │              │
│   │ - Store     │              │ - Messages  │              │
│   │ - Trade     │              │             │              │
│   └──────┬──────┘              └─────────────┘              │
│          │                                                     │
│          │ Commands, Trade Events                             │
│          ▼                                                     │
│   ┌────────────────────────┐                                  │
│   │  StoragePlugin         │  ← ANY bot can use this          │
│   │  (Business Logic)      │     via plugin system            │
│   └────────────┬───────────┘                                  │
└────────────────┼──────────────────────────────────────────────┘
                 │
┌────────────────┼──────────────────────────────────────────────┐
│              DATABASE LAYER                                   │
├─────────────────────────────────────────────────────────────┤
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐      │
│  │ permissions  │  │   chests     │  │  shulkers    │      │
│  └──────────────┘  └──────────────┘  └──────────────┘      │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐      │
│  │ shulker_items│  │   trades     │  │  item_index  │      │
│  └──────────────┘  └──────────────┘  └──────────────┘      │
└────────────────┼──────────────────────────────────────────────┘
                 │ (SQLite: ./storage/storage.db)
┌────────────────┼──────────────────────────────────────────────┐
│               WEB LAYER (24/7)                                │
├─────────────────────────────────────────────────────────────┤
│  ┌──────────────┐         ┌──────────────┐                  │
│  │  Express     │────────▶│  Web UI      │                  │
│  │  Server      │  API    │  (HTML/JS)   │                  │
│  └──────────────┘         └──────────────┘                  │
│        ▲                                                     │
│        │ REST API                                            │
│        │                                                     │
│  /api/inventory, /api/chests, /api/withdraw, ...           │
└─────────────────────────────────────────────────────────────┘

Plugin Structure (Bot-Agnostic)

// Configuration in conf/secrets.js
"mc": {
    "bots": {
        "ez": {
            "plugins": {
                "Storage": {
                    // Bot can be swapped anytime
                }
            }
        },
        // Another bot can use Storage plugin:
        "art": {
            "plugins": {
                "Storage": {
                    // Different location, same functionality
                }
            }
        }
    }
}

Database Schema

Tables

permissions

Manage access to the storage system.

CREATE TABLE permissions (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    player_name TEXT UNIQUE NOT NULL,
    role TEXT DEFAULT 'team' NOT NULL CHECK(role IN ('owner', 'team', 'readonly')),
    joined_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Column Type Description
id INTEGER Primary key
player_name TEXT Minecraft username (unique)
role TEXT 'owner', 'team', or 'readonly'
joined_at TIMESTAMP When player was added

chests

Tracked chest blocks in storage area.

CREATE TABLE chests (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    pos_x INTEGER NOT NULL,
    pos_y INTEGER NOT NULL,
    pos_z INTEGER NOT NULL,
    chest_type TEXT NOT NULL CHECK(chest_type IN ('single', 'double')),
    row INTEGER NOT NULL,              -- 1-4 (vertical)
    column INTEGER NOT NULL,           -- horizontal grouping
    category TEXT,                     -- 'minerals', 'food', etc.
    last_scan TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UNIQUE(pos_x, pos_y, pos_z)
);

shulkers

Shulker boxes stored in chests.

CREATE TABLE shulkers (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    chest_id INTEGER NOT NULL,
    slot INTEGER NOT NULL,             -- 0-53 (single) or 0-107 (double)
    shulker_type TEXT DEFAULT 'shulker_box',
    category TEXT,                     -- 'minerals', 'tools', etc.
    item_focus TEXT,                   -- Item type stored (e.g., 'diamond')
    slot_count INTEGER DEFAULT 27,     -- Used slots (1-27)
    total_items INTEGER DEFAULT 0,     -- Total item count
    last_scan TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (chest_id) REFERENCES chests(id) ON DELETE CASCADE
);

shulker_items

Items inside shulker boxes. Enforces one item type per shulker.

CREATE TABLE shulker_items (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    shulker_id INTEGER NOT NULL,
    item_name TEXT NOT NULL,
    item_id INTEGER NOT NULL,
    slot INTEGER NOT NULL,             -- 0-26 (shulker slots)
    count INTEGER NOT NULL,
    nbt_data TEXT,                     -- JSON: {enchantments: [...], damage: 5}
    FOREIGN KEY (shulker_id) REFERENCES shulkers(id) ON DELETE CASCADE,
    UNIQUE(shulker_id, item_id),
    CHECK(slot >= 0 AND slot <= 26),
    CHECK(count > 0 AND count <= 64)
);

trades

Trade history logs.

CREATE TABLE trades (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    player_name TEXT NOT NULL,
    action TEXT NOT NULL CHECK(action IN ('deposit', 'withdraw')),
    items TEXT NOT NULL,               -- JSON: [{name, count, nbt}, ...]
    timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

pending_withdrawals

Withdrawal requests from players (sync between web and in-game).

CREATE TABLE pending_withdrawals (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    player_name TEXT NOT NULL,
    item_id INTEGER NOT NULL,
    item_name TEXT NOT NULL,
    requested_count INTEGER NOT NULL,
    status TEXT DEFAULT 'pending' CHECK(status IN ('pending', 'ready', 'completed', 'cancelled')),
    timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

item_index

Cached aggregated item counts for fast searches.

CREATE TABLE item_index (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    item_id INTEGER UNIQUE NOT NULL,
    item_name TEXT NOT NULL,
    total_count INTEGER DEFAULT 0,
    shulker_ids TEXT,                 -- JSON: [{id, count}, ...]
    last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

File Structure

nodejs/
├── controller/
│   ├── storage/
│   │   ├── index.js                 # StoragePlugin main class
│   │   ├── database.js              # SQLite setup and all DB operations
│   │   ├── scanner.js               # Chest discovery and scanning
│   │   ├── organizer.js             # Item sorting and categorization
│   │   └── web.js                   # Express server (24/7 API)
│   ├── storage.js                   # Export for mc-bot.js plugin loading
│   └── commands/
│       ├── default.js               # Add: summon, dismiss commands
│       └── trade.js                 # Add StoragePlugin special handling
├── storage/
│   ├── storage.db                   # SQLite database (automatically created)
│   └── public/
│       ├── index.html               # Web UI (single page)
│       ├── app.js                   # Frontend logic
│       └── style.css                # Styling
├── conf/
│   ├── base.js                      # Add storage config
│   └── secrets.js                   # DB path, permissions init
└── ...

Component Specifications

1. StoragePlugin (controller/storage/index.js)

Purpose: Main plugin class that ties together database, scanner, organizer, and trade handling.

Constructor Arguments:

  • bot: The CJbot instance
  • dbFile: Path to SQLite database
  • homePos: Starting position (optional, auto-detect on first scan)

Key Methods:

class StoragePlugin {
    constructor(args) { ... }

    async init() {
        // Initialize database
        // Register commands
        // Start on bot 'onReady'
    }

    async unload() {
        // Clean up
    }

    async scanArea(force = false) {
        // Discover chests within render distance
        // Update database
    }

    async handleTrade(playerName, itemsReceived) {
        // Process incoming trade items
        // Sort into shulkers
        // Update database
    }

    async handleWithdrawRequest(playerName, itemId, count) {
        // Gather items to OUTBOX shulker
        // Mark as ready for pickup
    }

    async organize() {
        // Full re-sort (manual command)
    }
}

2. Database Module (controller/storage/database.js)

Purpose: All SQLite operations.

Key Functions:

// Initialize
async initialize(dbFile)

// Permissions
async addPlayer(name, role = 'team')
async removePlayer(name)
async getPlayerRole(name)
async getAllPlayers()
async checkPermission(name, requiredRole)

// Chests
async upsertChest(position, chestType)
async getChests()
async deleteOrphanChests()

// Shulkers
async upsertShulker(chestId, slot, category, itemFocus)
async getShulkersByChest(chestId)
async findShulkerForItem(itemId)  // Find shulker with same item and space
async createEmptyShulker(chestId, slot)
async updateShulkerCounts(shulkerId, slotCount, totalItems)

// Shulker Items
async upsertShulkerItem(shulkerId, item)
async getShulkerItems(shulkerId)
async deleteShulkerItem(shulkerId, itemId)

// Trades
async logTrade(playerName, action, items)
async getRecentTrades(limit = 50)

// Pending Withdrawals
async queueWithdrawal(playerName, itemId, itemName, count)
async getPendingWithdrawals(playerName)
async updateWithdrawStatus(id, status)
async markCompletedWithdrawals(playerName)

// Item Index
async updateItemCount(itemId, shulkerId, count)
async searchItems(query = null)
async getItemDetails(itemId)

3. Scanner Module (controller/storage/scanner.js)

Purpose: Discover and scan chests/shulkers.

Key Functions:

async discoverChests(bot, radius) {
    // Find all chest blocks within radius
    // Detect single vs double
    // Assign row/column based on position
    // Return array of chest positions
}

async scanChest(bot, chestPosition) {
    // Open chest
    // Read all slots
    // Scan any shulkers found
    // Update database
}

async scanShulker(bot, chestSlot, chestPosition) {
    // Click shulker to open
    // Read all 27 slots
    // Parse NBT data
    // Return item array
}

function detectChestType(position) {
    // Check adjacent blocks to detect double chest
    // Return 'single' or 'double'
}

function assignRowColumn(position, minPos) {
    // Calculate row from Y (1-4)
    // Calculate column from X/Z
    // Return {row, column}
}

4. Organizer Module (controller/storage/organizer.js)

Purpose: Sort items into shulkers, categorize items.

Key Functions:

function categorizeItem(itemName) {
    // Returns: 'minerals', 'food', 'tools', 'armor', 'blocks', 'redstone', 'misc'
}

async sortItems(itemsDb, itemsToSort) {
    // For each item:
    //   - Find shulker with same item AND space
    //   - If found: move to that shulker, consolidate stacks
    //   - If not found: create new shulker at category column
    // Return: moves to execute
}

function findCategoryColumn(category, row) {
    // Map (category, row) to chest column
    // Return column number
}

async consolidateStacks(shulkerId) {
    // Merge partial stacks
    // Update database
}

5. Web Server (controller/storage/web.js)

Purpose: Express API for 24/7 inventory access.

API Endpoints:

GET  /api/inventory
GET  /api/inventory/:itemId
GET  /api/chests
GET  /api/chests/:id
GET  /api/shulkers
GET  /api/shulkers/:id
GET  /api/stats
GET  /api/trades?limit=50
POST /api/withdraw
GET  /api/pending/:playerName
POST /api/auth

Detailed API Spec:

GET /api/inventory
Response: {
    items: [
        {
            item_id: 1,
            item_name: "diamond",
            total_count: 2304,
            locations: [
                {shulker_id: 1, count: 1728},
                {shulker_id: 5, count: 576}
            ]
        },
        ...
    ]
}

GET /api/inventory/:itemId
Response: {
    item_id: 1,
    item_name: "diamond",
    total_count: 2304,
    locations: [
        {
            shulker_id: 1,
            chest_id: 3,
            chest_pos: {x: 100, y: 64, z: 200},
            count: 1728
        },
        ...
    ]
}

GET /api/chests
Response: {
    chests: [
        {
            id: 1,
            pos_x: 100, pos_y: 64, pos_z: 200,
            chest_type: "double",
            row: 1,
            column: 1,
            category: "minerals",
            shulker_count: 26
        },
        ...
    ]
}

GET /api/stats
Response: {
    totalItems: 15432,
    totalShulkers: 156,
    totalChests: 24,
    emptyShulkers: 12,
    categories: {
        minerals: 42,
        food: 18,
        tools: 24,
        ...
    },
    recentTrades: [
        {player: "wmantly", action: "deposit", item_count: 45, time: "..."}
    ]
}

POST /api/withdraw
Body: {player_name: "wmantly", item_id: 1, count: 64}
Response: {success: true, withdraw_id: 123}

GET /api/pending/:playerName
Response: {
    pending: [
        {
            id: 123,
            item_name: "diamond",
            requested_count: 64,
            status: "ready"
        }
    ]
}

6. Web UI (storage/public/)

index.html: Single page application

  • Search bar
  • Filter by category
  • Item list with counts
  • Click to see details (shulker locations)
  • "Request Withdraw" button (opens modal)
  • Stats sidebar

app.js: Frontend logic

  • Fetch API calls
  • Search/filter logic
  • Withdraw request modal
  • Auto-refresh pending withdrawals

style.css: Simple, clean styling

7. Modified Commands

default.js - Add new commands:

'summon': {
    desc: 'Summon a bot online indefinitely',
    allowed: ['owner'],
    ignoreLock: true,
    async function(from, botName) { ... }
},
'dismiss': {
    desc: 'Send a bot offline',
    allowed: ['owner'],
    ignoreLock: true,
    async function(from, botName) { ... }
},

trade.js - Add StoragePlugin handling:

module.exports = {
    '.trade': {
        desc: 'Bot will take trade requests',
        async function(from) {
            // Check if bot has StoragePlugin
            if (this.plunginsLoaded['Storage']) {
                await this.plunginsLoaded['Storage'].handleTrade(from, ...);
            } else {
                // Original sign-based flow
                let chestBlock = findChestBySign(this, from);
                // ...
            }
        }
    }
}

Configuration

conf/base.js

"storage": {
    // Database location
    "dbPath": "./storage/storage.db",

    // Chest discovery
    "scanRadius": 30,                 // Render distance
    "homePos": null,                  // Auto-detect on first scan

    // Category mappings
    "categories": {
        "minerals": ["diamond", "netherite_ingot", "gold_ingot", "iron_ingot",
                     "copper_ingot", "emerald", "redstone", "lapis_lazuli"],
        "food": ["bread", "cooked_porkchop", "steak", "golden_apple", "cooked_beef",
                "cooked_chicken", "cooked_mutton", "carrot", "potato", "baked_potato"],
        "tools": ["wooden_sword", "stone_sword", "iron_sword", "diamond_sword",
                "netherite_sword", "wooden_pickaxe", "stone_pickaxe", "iron_pickaxe",
                "diamond_pickaxe", "netherite_pickaxe", "wooden_axe", "stone_axe",
                "iron_axe", "diamond_axe", "netherite_axe"],
        "armor": ["leather_helmet", "iron_helmet", "diamond_helmet", "netherite_helmet",
                  "leather_chestplate", "iron_chestplate", "diamond_chestplate", "netherite_chestplate",
                  "leather_leggings", "iron_leggings", "diamond_leggings", "netherite_leggings",
                  "leather_boots", "iron_boots", "diamond_boots", "netherite_boots"],
        "blocks": ["stone", "dirt", "cobblestone", "oak_planks", "spruce_planks",
                   "birch_planks", "oak_log", "spruce_log", "cobblestone_stairs"],
        "redstone": ["redstone", "repeater", "comparator", "piston", "sticky_piston",
                     "redstone_torch", "lever", "tripwire_hook"],
        "misc": []  // Everything else falls here
    },

    // Special shulkers (for bookkeeping)
    "inboxShulkerName": "INBOX",
    "outboxShulkerName": "OUTBOX",
    "newShulkersName": "EMPTY",

    // Web server
    "webPort": 3000,
    "webHost": "0.0.0.0"
}

conf/secrets.js

"storage": {
    // Database can override location
    // "dbPath": "./storage/storage.db",

    // Default permissions (inserted on DB init)
    "defaultPlayers": [
        {name: "wmantly", role: "owner"},
        {name: "useless666", role: "owner"},
        {name: "tux4242", role: "owner"},
        {name: "pi_chef", role: "team"},
        {name: "Ethan", role: "team"},
        {name: "Vince_NL", role: "team"}
    ]
}

Bot Configuration (Plugin-Based, Bot-Agnostic)

// conf/secrets.js - Example: ez bot
"mc": {
    "bots": {
        "ez": {
            "username": "mc3@vm42.us",
            "auth": "microsoft",
            "commands": ['default'],
            "autoConnect": false,
            "plugins": {
                "Storage": {
                    // Bot uses Storage plugin
                }
            }
        },
        // Any bot can be moved to storage location:
        "art": {
            "username": "art@vm42.us",
            "auth": "microsoft",
            "plugins": {
                "Storage": {
                    // Same plugin, different bot
                }
            }
        }
    }
}

User Workflows

Deposit Flow (Player Perspective)

  1. Player collects items from farms/raids (max 12 slots due to trade window)
  2. Player types: /msg ez trade or uses /trade command with ez
  3. Trade window opens
  4. Player puts items in their side of trade window
  5. Confirm trade
  6. ez automatically:
    • Moves all items to INBOX shulker
    • Categorizes each item
    • Finds appropriate shulker (creates new if needed)
    • Moves items to organized shulkers
    • Updates database
  7. ez whispers: Received X items. Stored successfully.
  8. Player can verify on web: http://server:3000

Withdraw Flow (Player Perspective)

Option A: In-Game Only

  1. Player types: /msg ez withdraw diamond 64
  2. ez searches database for diamond locations
  3. ez gathers items to OUTBOX shulker
  4. ez whispers: Items ready for pickup. /trade with me.
  5. Player trades with ez
  6. ez moves items from OUTBOX to trade window
  7. Confirm trade
  8. ez updates database

Option B: Web Request

  1. Player visits web: http://server:3000
  2. Finds item and enters count
  3. Click "Withdraw"
  4. Queues request to database
  5. When ez is online, processes pending requests
  6. ez whispers player: Your items are ready. /trade with me.

Admin Workflow (Owner)

/msg ez summon                # Bring bot online
/msg ez dismiss               # Send bot offline
/msg ez scan                  # Force chest scan
/msg ez chests                # List tracked chests
/msg ez organize              # Force full re-sort
/msg ez status                # Show storage stats
/msg ez addplayer <name>      # Add authorized player
/msg ez removeplayer <name>   # Remove player
/msg ez players               # List authorized players

Security Considerations

Database Security

  • SQLite file permissions: Read/write by bot process only
  • No direct SQL injection (parameterized queries throughout)
  • Web API uses read-only connections for GET requests

Game Security

  • Bot location kept secret (no /tp to chests allowed to team)
  • Only trade window access for players
  • No /msg command execution to other bots

Web Security

  • No login required (simpler)
  • Auth via whisper challenge code (6-digit code generated, whispered to player for verification)
  • Rate limiting on API endpoints
  • CORS restricted to same origin

Implementation Plan

Phase 1: Core Database and Plugin Structure

  • Create database.js - SQLite setup and all queries
  • Create index.js - StoragePlugin main class skeleton
  • Initialize plugin in mc-bot.js via plugin system
  • Test: Database creation, basic connectivity

Phase 2: Scanner

  • Create scanner.js - Chest discovery and scanning
  • Scan loop: Find chests → Detect single/double → Assign row/column
  • Scan individual chests → Detect shulkers → Read NBT → Update DB
  • Test: Scan a test chest area, verify DB entries

Phase 3: Organizer

  • Create organizer.js - Categorization and sorting
  • Implement categorizeItem() function
  • Implement sort logic (find shulker, move items, create new if needed)
  • Test: Sort items from INBOX to organized shulkers

Phase 4: Trade Integration

  • Modify trade.js - Add StoragePlugin handling
  • Implement handleTrade() in StoragePlugin
  • Implement handleWithdrawRequest() in StoragePlugin
  • Test: Deposit and withdraw via trade window

Phase 5: Commands

  • Add summon, dismiss to default.js
  • Add storage commands (scan, status, chests, organize)
  • Add player management commands (addplayer, removeplayer, players)
  • Test: All commands work with proper permissions

Phase 6: Web Server

  • Create web.js - Express server
  • Implement API endpoints
  • Test: API returns correct data from database

Phase 7: Web UI

  • Create index.html - Single page UI
  • Create app.js - Frontend logic
  • Create style.css - Styling
  • Test: View inventory, search, request withdrawal

Phase 8: Integration Testing

  • Full deposit flow end-to-end
  • Full withdraw flow end-to-end
  • Web + in-game sync
  • Multiple trades in sequence
  • Database persistence after bot restart

Phase 9: Documentation and Polish

  • Update this doc with any changes
  • Add inline code comments
  • Error handling improvements
  • Performance optimization if needed

Dependencies

New npm packages required:

sqlite3         # SQLite database
express         # Web server
cors            # CORS handling (optional, for external API access)

Add to package.json:

{
  "dependencies": {
    "sqlite3": "^5.1.7",
    "express": "^4.19.2",
    "cors": "^2.8.5"
  }
}

Troubleshooting Guide

Database Issues

  • Database locked: Ensure only one process writes at a time
  • Corruption: Use sqlite3 storage.db "PRAGMA integrity_check;" to verify

Scan Issues

  • No chests found: Check homePos is correct, or bot is in render distance
  • Double chest detection fails: Ensure chests are properly adjacent

Trade Issues

  • Items not sorted: Check INBOX shulker exists and has space
  • Withdraw fails: Verify item exists in database with sufficient count

Web Issues

  • Can't access API: Check webHost (use 0.0.0.0 for external access)
  • Database not found: Ensure dbPath directory exists and has write permissions

Future Enhancements (Out of Scope for MVP)

  • Shulker color coding for categories (needs dye access, blocked by server rules)
  • Custom shulker names via NBT (blocked by server rules)
  • Partial shulker consolidation (current: one item type per shulker, no combining)
  • Auto-trading system (bot initiates trades)
  • Multi-location support (multiple storage areas)
  • Real-time web updates via WebSocket
  • Export inventory to CSV/JSON
  • Integration with trading APIs (like BulbaStore)
  • Recipe calculator (what can be crafted with current storage)
  • Value estimation (diamond equivalent of all items)

Glossary

Term Meaning
StoragePlugin The main plugin class that provides storage functionality to any bot
INBOX shulker Temporary holding shulker for incoming trade items
OUTBOX shulker Temporary holding shulker for items ready for withdrawal
EMPTY shulkers Reserve stock of new shulker boxes
One item type per shulker Each shulker stores only one item type (e.g., only diamonds)
Category Item group (minerals, food, tools, armor, blocks, redstone, misc)
Row/Column Chest positioning: Row (1-4, vertical), Column (horizontal grouping)
Render distance Distance within which bot can see/click chests