ItemGraph

A server-side forensic moderation mod for NeoForge 1.21.1. Reconstructs item movement, stack splits, and transformations through time from authoritative evidence.
Back to Files

ItemGraph 0.4.0 (NeoForge 1.21.1)

File nameitemgraph-0.4.0-neoforge.jar
Uploader
dwurdydwurdy
Uploaded
Oct 17, 2026
Downloads
7
Size
15.0 MB
Mod Loaders
NeoForge
File ID
9221361
Type
R
Release
Supported game versions
  • 1.21.1

Curse Maven Snippet

NeoForge

implementation "curse.maven:itemgraph-1699446:9221361"

Learn more about Curse Maven

What's new

[0.4.0] — 2026-10-17

Added

  • World and environmental causes (#55): both loaders now record confirmed explosion, piston, fluid, fire, Enderman block-movement, and falling-block state changes into ItemGraph-owned storage. Bounded snapshots preserve confirmed deltas and emit classified unresolved evidence when coverage is partial or callbacks fail. Blocked piston results are recorded as PISTON_BLOCK_ATTEMPT attempts separately from direct state deltas, and fire/fluid writes that return without a block-type change persist as WORLD_EFFECT_ATTEMPT with outcome=UNCHANGED. Throws with no confirmed block delta remain WORLD_EFFECT_UNRESOLVED. Enderman rows carry typed actor identity (entity:<type> id=<uuid>) separate from owner-provenance status, and audit rows render world/entity actor kinds instead of an unknown-player label. Events never invent player actors or item quantities; sensitive-location rows enforce itemgraph.audit through the taxonomy-driven lookup gate. The shared EventTaxonomy advances to 4.1.0 for the new event contract. NeoForge stages world-event capture at ServerAboutToStartEvent and Fabric opens capture before database initialization in SERVER_STARTING, so startup world events stay queued until the persistence worker can flush them.
  • Entity, projectile, and item-entity lifecycle causes (#56): both loaders now record fresh entity spawns (ENTITY_SPAWN), genuine removals (ENTITY_DESPAWN), non-player and world-cause kills (ENTITY_KILL), projectile launches and impacts (PROJECTILE_LAUNCH, PROJECTILE_IMPACT), and item-entity join/removal rows carrying the exact observed stack count (ITEM_ENTITY_SPAWN, ITEM_ENTITY_DESPAWN, quantity=SIGNED_DELTA). NeoForge uses EntityJoinLevelEvent.loadedFromDisk() and RemovalReason.shouldDestroy() so chunk loads and unloads never record spawn/despawn endpoints; Fabric reaches the same boundaries through addFreshEntity and a setRemoved capture because no Fabric events expose them. Projectile impact uses ProjectileImpactEvent on NeoForge and the game's own hitTargetOrDeflectSelf dispatch on Fabric. Non-player death drops now flow through the same settle-confirmed pending path as player drops — the dead entity replaces the player actor rather than inventing one — and a canceled drop event emits unresolved evidence. ENTITY_LIFECYCLE_UNRESOLVED preserves queue rejections and callback failures with reason codes. EventTaxonomy advances to 4.2.0.
  • Item-processing and economy transformations (issue #57). Trades, enchanting, brewing, smithing, grindstone, and loot-table generation now record observed input/output endpoints through the shared TransformationEvidence builder on both loaders. NeoForge uses the documented TradeWithVillagerEvent, PlayerEnchantItemEvent, and GrindstoneEvent.OnTakeItem; brewing, smithing, and loot generation use justified shared mixin boundaries (BrewingStandBlockEntity.doBrew, SmithingMenu.onTake, LootTable.getRandomItemsRaw) because no documented event supplies the required position, inputs, or result. Loot rows carry the table id resolved through Registries.LOOT_TABLE plus context actor/block/ tool provenance. Cancelled operations persist outcome=CANCELLED with TRANSFORMATION_CANCELLED; unobserved inputs and NeoForge's unobservable grindstone output stay explicit instead of guessed. A queue-rejected or failed callback emits TRANSFORMATION_UNRESOLVED with TRANSFORMATION_EVIDENCE_NOT_SUBMITTED. Absent endpoints use the explicit itemgraph:non_item_endpoint sentinel — never a fabricated stack.
  • GriefLogger coexistence and automatic migration (issue #203). ItemGraph and GriefLogger can now run on the same server: the SQLite driver ships as an opaque META-INF/iglibs/ resource loaded in a private, platform-parented classloader (com.itemgraph.db.SqliteJdbc), so no org.sqlite.* class sits on ItemGraph's module or classpath to collide with the copy inside the GriefLogger jar. NeoForge declares GriefLogger type="optional" with ordering="AFTER"; Fabric lists it under suggests. When the GriefLogger mod is detected at server start, ItemGraph enables the read-only source bridge automatically (grieflogger_auto_migrate, default true), resolves the source to GriefLogger's real config/grieflogger/database.db, queues the historical import once, and keeps polling new rows on the existing 60-second ingestion worker — no restart-with-removed-jar dance required. Set grieflogger_auto_migrate=false to run both mods with the bridge off, or keep grieflogger_integration_enabled=true for a retained database after the mod is removed. A GriefLogger useMysql=true configuration logs a warning since only the on-disk SQLite file is importable. /ig status reports the auto-detected migration state. Query cancellation no longer binds org.sqlite.* types — the dispatcher interrupts timed-out queries through JDBC Statement.cancel() plus a reflective connection interrupt.
  • Opt-in automation adapter contract (issue #34): AutomationEndpoint provides restart-stable opaque inventory identities derived from mod, dimension, position, slot policy, and side, plus opt-in Fabric FabricTransferStorageAdapter and NeoForge NeoForgeItemHandlerAdapter implementations. They preserve native transfer results, record exact committed quantities, and suppress simulations and rollbacks. Fabric overflow omits the whole transaction; source mod identity is checked against its registered handle, and caller-created endpoints cannot add a location to the opaque reference. Rejected transfers, zero movement, and impossible quantity claims emit no movement evidence. Explicit QUEUE_FULL responses retry the same event identity at most three times through a 128-entry bounded worker queue; other outcomes are not replayed. This is in-memory retry only, and pending retries can be interrupted by process shutdown. Vanilla hopper transfers emit bounded endpoint-unknown net deltas on both loaders (HOPPER_INSERT/HOPPER_EXTRACT); NeoForge IItemHandler capability deltas persist as CAPABILITY_INSERT/CAPABILITY_EXTRACT at the changed endpoint, and committed adapter-API transfers persist as TRANSFER_ITEM. All three automation action IDs are now classified in EventTaxonomy instead of rendering unclassified. Both loaders record accepted default-behavior dispenser/dropper outputs (DISPENSER_DROP/DROPPER_DROP) with source, item, amount, ground endpoint, and entity UUID. Snapshot bounds use overflow-safe arithmetic, and unreadable prior hopper snapshots suppress paired deltas. NeoForge adapters accept mod-owned opaque inventory IDs for item-handler providers without deriving identity from an ItemStack. Cross-loader test consumers move stacks through Fabric Transfer API and NeoForge item-capability adapters between portable and shulker-like storage and assert both persisted endpoint deltas. These are vanilla/API fixtures, not third-party backpack integrations. Arbitrary modded inventories still require an exercised supported adapter. Bounded queue saturation and concurrent rejection tests verify the 128-entry queue and visible QUEUE_FULL. Native hopper/dispenser captures use an additional 1,024-entry bounded backpressure queue on the same database worker; /ig status reports pending rows and explicit exhaustion, and shutdown flushes both queues. Saturation tests verify native capture retention and persistence after the primary 10,000-entry observation queue fills.

Changed

  • Default grieflogger_database_path resolution. The default value database.db now resolves to config/grieflogger/database.db (where GriefLogger actually writes) whenever the mod is detected or the file exists, instead of <game directory>/database.db. Explicitly configured paths are unchanged.
  • Ingestion schema gate. No change: a GriefLogger source file that exists but lacks the supported schema continues to be skipped after one log line per disappearance.

This mod has no additional files