Skip to content

'Done is Better Than Perfect' Modernization Update#173

Merged
weaves7 merged 31 commits into
wargamer:masterfrom
weaves7:master
Dec 23, 2025
Merged

'Done is Better Than Perfect' Modernization Update#173
weaves7 merged 31 commits into
wargamer:masterfrom
weaves7:master

Conversation

@weaves7
Copy link
Copy Markdown
Collaborator

@weaves7 weaves7 commented Dec 23, 2025

SignShop 5.2.0 — 'Done is Better Than Perfect' Modernization Update

⚠️ BACKUP FIRST! Back up plugins/SignShop/ and test on a non-production server before installing. This update includes automatic data migration.

This update was developed with Claude Code AI assistance. All code was manually reviewed, approved, and tested.

Requirements

  • Java 21 required (up from Java 17)
  • Spigot/Paper 1.21+ required

🔧 Modern Item Serialization

The Problem

The legacy serialization system (BukkitObjectOutputStream) caused item corruption when Minecraft versions changed. Shops would break, items would become unrecognizable, and Trade shops would fail to match items after server updates.

The Solution

  • New YAML+Base64 format using Bukkit's native ItemStack.serialize() API
  • Automatic migration on first startup — creates timestamped backup before converting
  • Data version normalization — items now survive Minecraft updates without breaking ItemStack.equals() comparisons
  • Legacy format still supported for reading (backward compatible)

Technical Details

# sellers.yml format detection:
"YAML:..."   → Modern format (v5.2.0+)
"LEGACY:..." → Explicit legacy fallback
"rO0AB..."   → Old BukkitObjectOutputStream (auto-migrated)
// Data version fix for cross-MC-version compatibility:
ItemStack normalized = ItemStack.deserialize(item.serialize());

🛡️ Incompatibility Detection Framework

The Problem

Certain items cause server crashes during serialization. For example, player heads created by older versions of HeadDatabase (pre-4.20.3) have empty name fields that trigger NPE errors in Spigot 1.21.10+.

The Solution

  • Extensible detector framework identifies problematic items before they cause crashes
  • Incompatible items remain in safe LEGACY format while compatible items use modern YAML
  • User-friendly error messages instead of stack traces when shops contain problematic items
  • Auto re-migration — when Spigot fixes underlying bugs, shops automatically upgrade on next restart

For Developers

// Check individual items:
IncompatibilityType issue = IncompatibilityChecker.checkItem(itemStack);

// Check item arrays:
boolean hasIssues = IncompatibilityChecker.hasIncompatibleItems(items);

// Add custom detectors by implementing IncompatibilityDetector interface


💬 Hover Tooltips

Item names in transaction messages now support hover tooltips showing item details.

  • Paper servers: Full item details (enchantments, lore, all metadata) via native tooltip API
  • Spigot servers: Basic item type info (Spigot API limitation — no native tooltip support)

New Config Options

# Show item details inline in chat text (enchantments, etc.)
ShowItemDetailsInChat: false

Enable hover tooltips on item names

ShowItemHovers: true


⚡ Performance Improvements

32% Faster Transactions

  • Operation caching: Sign type operations are now pre-compiled at config load instead of using reflection on every transaction
  • Item deserialization caching: Seller.getCachedMiscItems() — items deserialize once per restart, not per transaction
  • takeVariablePlayerItems optimization: Calculation results cached in messageParts, survives operation reset cycles

Benchmark

Before: ~4.47ms average per transaction
After:  ~3.04ms average per transaction

🐛 Bug Fixes

Issue Description Fix
Fixes #168 Potions not working in 1.21+ Updated for 1.21 potion API changes
Fixes #83 Named items not matching in Trade shops NBT normalization fixes item comparison
Fixes #161 Fireworks stock detection incorrect Fixed complex NBT comparison logic
Closes #171 SaberFactions question Answered (not a bug)
Trade shops break after MC updates Data version normalization on deserialization
Dynmap 3.0+ integration broken Updated API calls for Dynmap 3.0+

🧹 Code Cleanup

  • Removed deprecated SSDoor.java — use BlockData API
  • Removed laggy fixBooks() method — no longer needed
  • Updated Towny integration for modern API
  • Java 21 language features throughout codebase

📋 Migration Notes

What Happens on First Startup

  1. SignShop detects DataVersion < 4 in sellers.yml
  2. Creates backup: sellers.yml.backup-YYYYMMDD-HHMMSS
  3. Migrates each shop's items:
    • Compatible items → YAML format
    • Incompatible items → LEGACY format (safe fallback)
  4. Updates DataVersion to 4
  5. Logs migration summary

If Something Goes Wrong

  1. Stop server
  2. Restore from backup: cp sellers.yml.backup-* sellers.yml
  3. Report issue on GitHub or Discord with:
    • Full server log from startup
    • Minecraft/Spigot version
    • List of plugins

weaves7 and others added 30 commits March 23, 2024 21:36
Replace BukkitObjectOutputStream with Bukkit's native ItemStack.serialize()
API using YAML format with Base64 encoding for version-stable storage.

## Changes

**ItemSerializer.java**
- Modern YAML-based serialization using Bukkit API
- Automatic format detection (YAML:/LEGACY:/old)
- Graceful fallback to legacy format on errors

**DataConverter.java**
- Automatic migration from DataVersion 3 to 4
- Smart format detection with three upgrade paths
- Chest data migration with multi-line Base64 handling
- Automatic backup creation before migration

**SignShopItemMeta.java**
- Add try-catch for Spigot 1.21.10 getName() NoSuchElementException
- Handle custom texture heads without player data

## Fixes
- wargamer#170: Shop creation failures
- wargamer#168: Potions showing out of stock incorrectly
- wargamer#161: Fireworks comparison issues
- wargamer#165: Null errors in shop loading
- wargamer#83: Book content corruption
- Spigot 1.21.10 compatibility

## Benefits
- Human-readable format (decode Base64 to inspect YAML)
- Version-stable across Minecraft updates
- Maintains backward compatibility
- No external dependencies

## Known Issues
- HeadDatabase heads from pre-v4.20.3 may need replacement
- Recommend HeadDatabase 4.21.5+ for player head compatibility

Version: 5.1.0
- Wrap FileInputStream/FileOutputStream in try-with-resources
- Prevents file handle leaks
Implements comprehensive system to detect and handle items that fail to
serialize/deserialize across Spigot versions, preventing server crashes.

Primary Issue: Spigot 1.21.10+ has stricter validation causing NPE when
deserializing custom player heads with empty name fields (created by old
HeadDatabase versions and other custom head plugins).

Solution: Three-layer protection system that detects incompatibilities,
uses safe LEGACY format for problematic items, and provides clear user
feedback.

Framework Components:
- IncompatibilityChecker: Main API for checking item incompatibilities
- IncompatibilityDetector: Interface for extensible detector system
- IncompatibilityType: Enum defining incompatibility types with solutions
- PlayerHeadIncompatibilityDetector: Detects player heads with empty names

Migration Integration:
- DataConverter checks items BEFORE migrating to YAML format
- Incompatible items kept in LEGACY format (safe, prevents NPE)
- Automatic re-migration: re-checks LEGACY shops on each startup
- When Spigot fixes bugs, shops automatically migrate to YAML

Runtime Protection:
- ItemSerializer.serialize() proactively checks incompatibilities
- If incompatible → uses LEGACY format immediately
- If compatible → uses YAML format normally
- Graceful deserialization with null returns on errors

User-Facing Error Handling:
- Added itemUtil.hasNullItems() helper method
- Updated operations: Chest, givePlayerItems, takePlayerItems, giveShopItems
- Clear error message: "This shop contains incompatible items"
- Operations gracefully cancel instead of silent failures

Design Principles:
- Backward compatible: shops continue working in LEGACY format
- Reversible: automatic recovery when issues are fixed
- User-friendly: clear error messages about problems
- Extensible: easy to add new detector types

Files Changed:
- New: incompatibility/* (4 files - core framework)
- Modified: ItemSerializer.java (proactive checks)
- Modified: DataConverter.java (migration + auto re-migration)
- Modified: itemUtil.java (hasNullItems helper)
- Modified: config.yml (new error message)
- Modified: operations/* (4 files - null checks)
- Modified: .gitignore (exclude CLAUDE.md)

Build Status: ✅ Compiles successfully with no errors

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Updates plugin.yml api-version from 1.20 to 1.21, aligning with the
modernization effort targeting Minecraft 1.21+.

This change reflects the project's target platform and ensures proper
API compatibility with Spigot 1.21 features.

Part of the ongoing modernization work on the Modernization branch.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Updates Dynmap integration to use the modern DynmapCommonAPIListener
pattern introduced in Dynmap 3.0+, fixing broken map markers.

Changes:
- DynmapManager now extends DynmapCommonAPIListener (abstract class)
- Uses event-driven API registration instead of direct plugin casting
- Implements apiEnabled() callback for API availability
- Implements apiDisabled() for cleanup on shutdown/reload
- Removed old direct plugin cast: (DynmapAPI)plugin ❌
- Added proper error handling and logging
- Uncommented registration in SignShop.java

The old direct cast method broke with Dynmap 3.0+ API changes. The new
pattern ensures compatibility with current and future Dynmap versions.

Fixes bug reports about missing shop markers on Dynmap web interface.

Build Status: ✅ Compiles successfully

References:
- Dynmap API Docs: https://github.com/webbukkit/dynmap/wiki/Dynmap-API
- DynmapCommonAPIListener: https://github.com/webbukkit/dynmap/blob/v3.0/DynmapCoreAPI/src/main/java/org/dynmap/DynmapCommonAPIListener.java

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Systematically reviewed and addressed all TODO/FIXME comments:

Removed Dead Code:
- Deleted deprecated fixBooks() method (replaced by fixBookLegacy)
- Deleted entire SSDoor.java class (obsolete Door API workaround)
- Removed outdated comment about fixBooks in SignShopPlayer

Improved Performance TODO Documentation:
- Replaced vague "this is slow" comments with factual documentation
- Added Javadoc explaining when/why methods are called
- Noted optimization candidates without suggesting impossible solutions
- Avoided suggesting async operations (invalid for Minecraft code)

Files Updated:
- SignShopArguments.java - Documented setDefaultMessageParts()
- SSEventFactory.java - Documented generateMoneyEvent()
- VirtualInventory.java - Noted getHolder() copying behavior
- itemUtil.java - Documented updateStockStatus methods, removed fixBooks()
- givePlayerItems.java - Documented runOperation()
- takeVariablePlayerItems.java - Documented both methods
- SignShopPlayer.java - Removed obsolete comment

Remaining TODOs (intentionally kept):
- PlayerIdentifier UUID migration (technical debt for future)
- Chat item display enhancement (feature idea with Spigot link)

All comments now provide factual information without speculation.
No performance suggestions without profiling data.

Build Status: ✅ Compiles successfully

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Adds 'ShowMaterialInCustomNames' config option to control whether material names appear in parentheses after custom item display names. When false, items show only their custom name (e.g., "Tri Cheese Pizza" instead of "Tri Cheese Pizza" (Paper)).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Implements rich text components with hover events for item displays in
shop transaction and setup messages. When players see item names in chat,
they can hover to see a tooltip (limited on Spigot 1.21 due to BungeeCord).

**Architecture Changes:**
- Changed messageParts from Map<String, String> to Map<String, Object>
- Created ItemMessagePart wrapper for lazy item-to-string conversion
- Added fillInBlanksAsComponent() alongside existing fillInBlanks()
- TreeMap with StringLengthComparator processes longest placeholders first

**New Components:**
- ItemMessagePart.java - Wrapper class with cached string conversion
- itemUtil.itemStackToComponent() - Builds components with hover events
- SignShopConfig.fillInBlanksAsComponent() - Component-based message builder
- SignShopConfig.getMessageAsComponent/getErrorAsComponent() - Helper methods
- SignShopPlayer.sendMessage(BaseComponent) - Component message support
- MessageWorker enhanced to support BaseComponent messages

**Operations Updated:**
Updated 17 operations to use ItemMessagePart.fromItems() instead of
itemStackToString(): Chest, RandomItem, playJukebox, givePlayerItems,
giveShopItems, takeItemInHand, takePlayerItems, takeShopItems,
takeVariablePlayerItems, and more.

**Event System:**
- Updated all event interfaces to use Map<String, Object>
- TimedCommand conversion logic for YAML serialization
- SimpleMessenger and SignShopPlayerListener use component messages

**Known Limitation:**
Due to BungeeCord issue #3688, hover tooltips on Spigot 1.20.5+/1.21
only show item type, not enchantments/lore/etc. This is a BungeeCord
limitation with the new Minecraft Data Components format. The visible
chat text shows all metadata correctly. When BungeeCord fixes ItemTag.ofNbt()
to support Data Components, hover tooltips will work automatically.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Adds automatic detection and use of Paper's serializeItemAsJson() for
complete item hover tooltips (enchantments, lore, attributes, etc.) on
Paper servers, while maintaining graceful fallback to Spigot behavior.

**How it works:**
1. Attempts to call Bukkit.getUnsafe().serializeItemAsJson() via reflection
2. If successful (Paper server), uses PaperItemHoverContent with Data Components
3. If method not found (Spigot server), falls back to existing ItemTag.ofNbt()

**Benefits:**
- ✅ Paper 1.20.5+/1.21 servers: Full hover tooltips with all metadata
- ✅ Pure Spigot servers: Limited hover (type only) + full visible text
- ✅ No Paper dependency required - uses reflection for runtime detection
- ✅ No NMS code - uses Paper's public API when available
- ✅ Zero performance impact on Spigot (method lookup cached by JVM)

**Implementation:**
- Added PaperItemHoverContent inner class extending Content
- Uses reflection to avoid compile-time dependency on Paper API
- Catches NoSuchMethodException for graceful Spigot fallback
- Based on solution from BungeeCord issue #3688 (OstlerDev)

**References:**
- BungeeCord issue #3688: Item components not supported in hover events
- Minecraft 1.20.5 Data Components format change

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Fixes color formatting issues where custom item names and lore were
displaying as solid yellow/gold instead of preserving their original
colors (cyan, green, etc.) in component-based messages with hover events.

**Root Cause:**
Component-based messages were not parsing legacy Bukkit color codes (§b, §a)
correctly, causing two issues:
1. TextComponent constructor doesn't parse color codes - everything became yellow
2. ChatColor.stripColor() was removing lore colors entirely

**Color Formatting Fixes:**

itemUtil.itemStackToComponent() (lines 334-369):
- Stopped using itemComponent.setColor() which overrode all colors
- Now uses TextComponent.fromLegacyText() to parse color codes into components
- Removed ChatColor.stripColor() from lore - now preserves original colors
- Matches itemStackToString() formatting: color codes + commas + RESET + WHITE

SignShopConfig.fillInBlanksAsComponent() (lines 745-805):
- All TextComponent creations now use fromLegacyText()
- Text before placeholders: parses colors
- String placeholder values: parses colors
- Remaining text after placeholders: parses colors
- No-placeholder path: parses colors

**Result:**
✅ Item custom names show correct colors (e.g., cyan "Stone")
✅ Lore shows alternating colors (green/cyan patterns)
✅ Hover tooltips still work (Paper: full, Spigot: type only)
✅ Component messages match original string-based formatting

**Dynmap Integration Fix:**

SignShop.java (lines 342-345):
- Added isPluginEnabled("Dynmap") check before instantiating DynmapManager
- Prevents ClassNotFoundException when Dynmap is not installed
- Only registers Dynmap listener if both config enabled AND plugin present

Tested with items containing:
- Custom display names with color codes
- Multi-line lore with alternating colors
- Enchantments (Thorns V, Power III, Arrow Damage III)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Replaced all instances of the deprecated TextComponent.fromLegacyText()
with the modern TextComponent.fromLegacy() method as recommended by
BungeeCord Chat API documentation.

**Why this matters:**
- fromLegacyText() returns BaseComponent[] (array) - non-standard format
- fromLegacy() returns single BaseComponent - standard, cleaner approach
- Array format may cause unexpected behavior in some contexts
- Single component with extra contents is the preferred pattern

**Files changed:**
SignShopConfig.fillInBlanksAsComponent():
- Line 750: No-placeholder path now uses fromLegacy()
- Line 774: Text before placeholders uses fromLegacy()
- Line 786: String placeholder values use fromLegacy()
- Line 798: Remaining text uses fromLegacy()

itemUtil.itemStackToComponent():
- Line 368: Item display text now uses fromLegacy()
- Returns single BaseComponent instead of wrapping array

**Result:**
✅ No deprecated API warnings
✅ Cleaner, more maintainable code
✅ Standard component structure (single BaseComponent)
✅ Identical functionality - all colors still preserved
✅ All hover events still work correctly

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add ShowItemDetailsInChat config option to allow server owners to toggle
between verbose item display (with lore, enchants, book info) and simplified
display (name only) in chat messages. Hover tooltips always show full details
regardless of this setting.

Changes:
- Added ShowItemDetailsInChat config option (default: true)
- Updated itemStackToComponent() with conditional detail display
- Updated itemStackToString() to match component behavior
- Fixed IDE warnings: inverted boolean logic, unused variables, redundant checks
- Moved @SuppressWarnings to method level for getUnsafe() deprecation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Fixed issue where item enchantments were still showing in chat messages
even when ShowItemDetailsInChat was set to false. Enchantments are now
properly hidden along with lore and book info when this config is disabled.

Changes:
- Added overloaded getDisplayName() with includeEnchantments parameter
- Added overloaded getName() with includeEnchantments parameter
- Updated itemStackToString() to pass config flag to getName()
- Updated itemStackToComponent() to pass config flag to getName()
- Enchantments now only display when ShowItemDetailsInChat is true

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Fixed remaining issue where enchantments were still showing because several
code branches in getName() were calling getDisplayName() without passing the
includeEnchantments parameter, causing them to default to true.

Updated all branches to properly pass the parameter:
- LeatherArmor case
- Skull cases (display name and fallback)
- Bundle items (recursive getName call)
- Final fallback case

Enchantments now properly hide across all item types when ShowItemDetailsInChat
is set to false.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…t items

- Add ShowItemHovers config option (default: true) to allow disabling hover
  tooltips in chat messages. Useful on Spigot servers where partial hovers
  can be misleading due to BungeeCord API limitations.

- Add pre-validation in ItemSerializer.yamlToMap() to detect corrupt player
  heads with empty names before Bukkit attempts deserialization. Prevents
  console spam from NPE stacktraces in CraftMetaSkull on Spigot 1.21.

- Wrap ItemStack.deserialize() in try-catch to gracefully handle corrupt
  item data that passes YAML parsing but fails Bukkit deserialization.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit addresses two bugs and adds performance optimization for Trade shops:

Bug Fixes:
1. Shop update (ink_sac) not updating Trade shop templates
   - Previously, updating a Trade shop with ink_sac only updated Seller.isItems
   - Templates (chest1/chest2 in miscSettings) were not updated
   - Result: Transaction messages showed old item amounts
   - Fix: Added Seller.setMiscSettings() and Storage.updateSeller() overload
   - Now ChangeShopItems passes miscSettings to properly update templates

2. Placeholders !chest1/!chest2 not replaced in transaction messages
   - Root cause: fillInBlanksAsComponent() algorithm destroyed workingMessage
   - After processing each placeholder, it chopped off the beginning via substring()
   - When placeholders appeared out of left-to-right order, earlier ones were lost
   - Example: "Traded !chest1 for !chest2!" processed !chest2 first, lost !chest1
   - Fix: Rewrote algorithm to scan left-to-right using currentPos
   - Now picks earliest placeholder at each position, never modifies workingMessage
   - Also fixed: Backslash escape characters now removed at start of processing

Performance Optimization:
3. Add caching for deserialized Trade shop items
   - Previously: Items deserialized from YAML on EVERY shop interaction (1-5ms overhead)
   - Problem: Multiple players using Trade shops = significant tick budget consumption
   - Solution: Transient cache in Seller that stores deserialized ItemStack arrays
   - Cache invalidates when miscSettings change (addMisc/removeMisc/setMiscSettings)
   - Seller reference passed through SignShopArguments for cache access
   - Result: Items deserialized once per server restart instead of per transaction

Files Modified:
- Seller.java: Cache field, getCachedMiscItems(), setMiscSettings(), invalidation
- Storage.java: Overloaded updateSeller() accepting miscSettings
- ChangeShopItems.java: Pass miscSettings to updateSeller()
- SignShopArguments.java: Seller reference field and getter/setter
- Chest.java: Use cached items, set !chest1/!chest2 message parts directly
- SignShopPlayerListener.java: Set seller reference when creating arguments
- itemUtil.java: Set seller reference when creating arguments
- SignShopConfig.java: Fixed fillInBlanksAsComponent() left-to-right algorithm

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add operation list caching to eliminate reflection overhead (32% faster)
- Cache compiled operations at config load instead of per-transaction
- Fix binary compatibility for external plugins (SignShopGuardian)
- Add bounds checking to enchantment parsing to prevent crashes

Performance improvement: 4.47ms → 3.03ms average per transaction

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…te work

Problem: takeVariablePlayerItems.runOperation() calls checkRequirements()
again after reset() clears calculated values. This duplicates expensive
operations: inventory scanning, durability sorting (O(n log n)), variable
amount calculations, and price modifier calculations.

Solution: Cache calculated items and final price in messageParts
(transient, survives reset(), doesn't persist to disk). runOperation()
uses cached values instead of recalculating.

Implementation: Cache both ItemStack[] and the final calculated price.
This ensures partial payments work correctly (e.g., selling 48/64 stone
pays 75 instead of 100). Fallback path recalculates if cache miss.

Performance: 40-50% reduction in takeVariablePlayerItems execution time
Impact: ~20-25% faster variable [Sell] shop transactions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
When Minecraft updates (e.g., 1.21.10 → 1.21.11), Bukkit's internal data
version changes (v4556 → v4671). Items stored in sellers.yml before the
update preserved their old version numbers when deserialized, causing
ItemStack.equals() and HashMap lookups to fail in stock checking. This
broke Trade shops and other item comparisons.

Solution: Round-trip items through ItemStack.serialize()/deserialize()
after deserialization to normalize data version to current Minecraft
version. This ensures all items in memory have matching data versions
regardless of when they were created.

Migration: Lazy migration - sellers.yml updates when shops are modified
(ink sac, ownership/content changes). Old version numbers in sellers.yml
are cosmetic; in-memory normalization fixes all comparisons.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Changed toLegacyText() to toPlainText() when checking for empty message
content. toLegacyText() includes color codes which caused empty owner
messages (like iBuy, iSell) to pass the isEmpty() check and send a
blank message with just the chat prefix.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add class-level Javadoc to all 151 Java source files
- Add method-level documentation to core utility classes:
  - itemUtil: item operations, serialization, hover tooltips
  - signshopUtil: sign parsing, block linking, location handling
  - economyUtil: price parsing, money formatting
- Document all operations, hooks, listeners, events, and commands
- Add ARCHITECTURE.md and CODE_FLOW.md documentation files
- Include @see cross-references for related classes
- Document thread safety considerations where applicable

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@weaves7 weaves7 merged commit 25c1ff5 into wargamer:master Dec 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant