Core Functions
Let's crack open the codebase and explore the essential functions that make DupeTrace tick. This is where the magic happens.
ItemIdUtil – UUID Tagging
File: src/main/kotlin/io/github/darkstarworks/dupeTrace/util/ItemIdUtil.kt
ensureUniqueId(plugin: JavaPlugin, item: ItemStack?): UUID?
ensureUniqueId(plugin: JavaPlugin, item: ItemStack?): UUID?The heart of item tracking. This function either retrieves or creates a UUID for an item.
Source (simplified):
fun ensureUniqueId(plugin: JavaPlugin, item: ItemStack?): UUID? {
if (item == null) return null
// Only non-stackable items get UUIDs
if (item.type.maxStackSize != 1) return null
val meta = item.itemMeta ?: return null
val container = meta.persistentDataContainer
val existing = container.get(key(plugin), PersistentDataType.STRING)
// Parse existing UUID or generate a new one
val id = if (existing.isNullOrBlank()) {
UUID.randomUUID()
} else {
runCatching { UUID.fromString(existing) }.getOrNull() ?: UUID.randomUUID()
}
// Store UUID in item's NBT data
container.set(key(plugin), PersistentDataType.STRING, id.toString())
item.itemMeta = meta
return id
}What's Happening:
Check if the item is non-stackable (
maxStackSize == 1)Look for an existing UUID in the PersistentDataContainer
If found, parse it; if invalid or missing, generate a new one
Store the UUID back into the item's NBT
Return the UUID (or null if the item is stackable/null)
Why This Works:
PersistentDataContainer survives everything: server restarts, player trades, chunk unloads
UUIDs are invisible to players (no lore spam)
Works on all non-stackable items: tools, armor, weapons, etc.
Edge Cases:
Stackable items (dirt, cobblestone) → returns
null(can't be tracked)Items without meta (air, barriers) → returns
nullCorrupted UUID strings → generates a fresh UUID
getId(plugin: JavaPlugin, item: ItemStack?): UUID?
getId(plugin: JavaPlugin, item: ItemStack?): UUID?Read-only version of ensureUniqueId(). Retrieves the UUID without modifying the item.
Source (simplified):
Use Cases:
Checking if an item is already tracked (without assigning a new UUID)
Reading UUIDs for comparison in duplicate detection
Command handlers that just need to display the UUID
DatabaseManager – Persistence Layer
File: src/main/kotlin/io/github/darkstarworks/dupeTrace/db/DatabaseManager.kt
recordSeen(id: UUID): Boolean
recordSeen(id: UUID): BooleanRecords that an item UUID has been seen. Returns true if this is the first time seeing this UUID (new item), false if it already existed (potential duplicate).
Source (simplified):
How It Works:
Uses PostgreSQL's
ON CONFLICT DO NOTHINGto avoid duplicate key errorsIf the UUID already exists, the insert is silently skipped (0 rows affected)
If the UUID is new, it's inserted (1 row affected)
Return Values:
true→ New item (first time seeing this UUID)false→ Existing item (UUID already in database)
Why This Matters: The return value tells us whether an item is legitimately new or suspiciously appearing again (possible duplicate).
logItemTransfer(itemUUID: String, playerUUID: UUID, action: String, location: String)
logItemTransfer(itemUUID: String, playerUUID: UUID, action: String, location: String)Logs every interaction with a tracked item.
Source (simplified):
Action Types:
PICKUP– Player picked up from groundDROP– Player dropped itemCRAFTED– Item was craftedINVENTORY_CLICK– Item clicked in inventoryCONTAINER_TRANSFER– Item moved to/from chestDEATH– Player died with itemENCHANT– Item was enchantedAnd many more (see ActivityListener.kt for full list)
Location Format: world:x,y,z (e.g., world:123,64,-456)
getItemTransferHistory(itemUUID: String, limit: Int = 100): List<TransferRecord>
getItemTransferHistory(itemUUID: String, limit: Int = 100): List<TransferRecord>Retrieves the full transfer history for an item, sorted by most recent first.
Source (simplified):
Returns:
Used By:
/dupetest uuidcommand (shows last 10 transfers)/dupetest historycommand (shows custom limit)Forensic investigations
getEarliestTransferTs(itemUUID: String, playerUUID: UUID): Long?
getEarliestTransferTs(itemUUID: String, playerUUID: UUID): Long?Returns the earliest timestamp when a specific player interacted with an item. Used to determine which player had the item first (for auto-removal logic).
Source (simplified):
Returns:
Long– Unix epoch milliseconds of the earliest interactionnull– No transfers found for this player/item combo
Used By:
Auto-removal logic when
keep-oldest-on-dup-remove: true
ActivityListener – Event Tracking & Duplicate Detection
File: src/main/kotlin/io/github/darkstarworks/dupeTrace/listener/ActivityListener.kt
tagAndLog(player: Player, item: ItemStack, action: String, loc: Location)
tagAndLog(player: Player, item: ItemStack, action: String, loc: Location)Central function called by most event handlers. Tags an item with a UUID and logs the interaction.
Source (simplified):
Flow:
Check if item already has a UUID
Ensure UUID is assigned
Recursively tag nested containers (Shulker Boxes, Bundles)
Record in database (async)
Log transfer (async)
If new item, notify watchers
Check for duplicates (the critical part!)
checkForDuplicates(itemId: String, currentPlayer: Player)
checkForDuplicates(itemId: String, currentPlayer: Player)The duplicate detection algorithm. Compares the current item location with the in-memory cache.
Conceptual Flow:
Grace Period Logic: The movement-grace-ms setting prevents false positives during legitimate item transfers:
Player picks up item → tracked at location A
100ms later, item appears in their inventory → same UUID, location B
Without grace period → FALSE POSITIVE (looks like a dupe)
With 750ms grace period → Ignored (within movement window)
This is why tuning movement-grace-ms is critical!
deepTagShulkerContentsIfAny(item: ItemStack)
deepTagShulkerContentsIfAny(item: ItemStack)Recursively tags items inside Shulker Boxes. Dupers love to hide duped items in nested containers, so we track everything.
Source (simplified):
Why This Matters: Without deep scanning, a duper could:
Duplicate a Shulker Box full of items
Items inside would have the same UUIDs
DupeTrace would only see the Shulker's UUID, missing the inner dupes
Deep scanning prevents this exploit.
startPeriodicScan()
startPeriodicScan()Starts a background task that periodically scans all online players' inventories for duplicates.
Source (simplified):
Why We Need This: Event tracking catches most duplicates, but some edge cases (like server lag, chunk loading, or creative mode exploits) can slip through. The periodic scanner acts as a safety net.
startKnownItemsCleanup()
startKnownItemsCleanup()Starts a background task that removes stale entries from the in-memory cache.
Source (simplified):
Why We Need This: Without cleanup, the knownItems map would grow forever, eventually causing memory issues. Items that haven't been seen in 10 minutes (default TTL) are removed from memory.
Note: Items are still tracked in the database – this only affects the in-memory cache used for duplicate detection.
Discord Integration
File: src/main/kotlin/io/github/darkstarworks/dupeTrace/webhook/DiscordWebhook.kt
sendDuplicateAlert(itemId: String, players: List<String>, locations: List<String>)
sendDuplicateAlert(itemId: String, players: List<String>, locations: List<String>)Sends a formatted alert to Discord when a duplicate is detected.
Example Webhook Payload:
Pretty neat for getting real-time alerts in your staff Discord channel!
Performance Optimization Tips
Use Async for Database Operations
Use ConcurrentHashMap for Shared State
Batch Database Operations When Possible
Instead of 100 individual inserts, consider batching (though DupeTrace currently uses individual inserts for simplicity).
What's Next?
Explore the data layer:
Database Schema → – Tables, indexes, and query patterns
Event System → – Complete list of tracked events
Got questions about a specific function? Check the inline KDoc comments in the source code or ask on Discord!
Last updated