Wubarrk-The_Eye icon

The Eye

A deterministic, cross-platform Valheim API extraction tool, vibe coders love it!

CHANGELOG

Changelog — The Eye

2.3.2 — 2026-09-25 (Valheim 1.0.16 compatibility)

Rebuilt against the Valheim 1.0.16 release assemblies (client build 25527674, dedicated server build 25527701, network version 40) and re-verified: a static reference check against both the client and dedicated-server assemblies, and a headless boot of the 1.0.16 dedicated server. No reader was broken - GameShape's BuildShape probe and every other late-bound member are unchanged from 1.0.15, and the only two members 1.0.16 removed (ObjectDB.GetAllFoodItems(), ButtonSfx.Start()) are not read by TheEye.

  • One comment corrected to stop naming a specific old build as if it were current: the ZNetScene.InActiveArea / OutsideActiveArea staticness note in ZDOExistencePatch.cs (verified unchanged against the 1.0.16 decompile).

2.3.1 — 2026-09-09 (Valheim 1.0.7 compatibility)

Rebuilt against the Valheim 1.0.7 release assemblies (client build 25185596, dedicated server build 25185644, network version 39) and BepInEx 5.4.2350, and loaded on the 1.0.7 Linux dedicated server with no Harmony, missing-member or type-load errors. No reader was broken by 1.0.7 - every member GameShape late-binds is still present or already had a fallback - but the instrument was blind to the release-stage sector change. Now it is not.

Manifest Compatibility gains BuildShape

  • The 1.0.7 release changed the sector API a second time after the 0.221.13 playtest: ZDOMan.FindSectorObjects(Vector2s, int area, int distantArea, ...) became FindSectorObjects(Vector2s, SimulationDistance, ...) and ZoneSystem.m_activeArea / m_activeDistantArea were removed. Nothing in the 2.3.0 probe looked at that shape, so a 2.3.0 dump could not tell the playtest from the release.
  • BuildShape records, as {Present, Shape} rows using type names (never typeof() on a type an older build may lack): ZDOMan.FindSectorObjects (arity and parameter types), the SimulationDistance struct, ZoneSystem.m_activeArea / m_activeDistantArea, ZNet.GetSyncedSimulationDistance(), ZoneSystem.SectorIndex, ZoneSystem.GetSectorIndex(Vector3), ZoneSystem.GetZone(Vector3), ZDOMan.SectorToIndex / ZoneSystem.SectorToIndex (moved, not removed), and a one-token SectorApi classification (pre-1.0 / 0.221.13 playtest / 1.0 release).
  • ZDO.GetSectorIndex() now records its return type; ZNetScene.InActiveArea / OutsideActiveArea record how many overloads are static. Absent BuildShape members are facts about the build, not blind readers: they never count towards the startup MISSING line.
  • New startup line [Eye.Compat] Build shape: ..., so a boot log alone answers which build this is.

Unchanged on purpose

  • Huginn's TypeOnlyRipple collapse still covers only Vector2i/Vector2s and Int16/Int32. The (int, int) -> SimulationDistance change is an arity change and keeps surfacing as a real signature change.
  • Stale comments refreshed (GameShape, Plugin.ApplyActiveAreaOverride, ZDOExistencePatch, HuginnsReport): the by-name attachment of the active-area prefixes is what survives 1.0 making ZNetScene.InActiveArea static.

2.3.0 — 2026-09-08 (the 1.0 migration release)

Built and verified against the Valheim 1.0 public-test build (0.221.13, build 23105022, network version 37) on a headless dedicated server, and against the last pre-1.0 server build.

Survives the build change

  • ZDO.GetSector() (now Vector2s), the seven removed ZDOExtraData.Get*s(ZDOID) readers (now GetData(out ...)), World.m_worldVersion (now an enum) and the ZNetScene.InActiveArea / OutsideActiveArea overloads are late-bound through GameShape. A missing member costs one field, never an extractor. Three strategies for ZDO data (GetData, Get*s, private dictionaries).
  • Manifest.json Compatibility section: every game member TheEye relies on, present or MISSING, plus the ZDO data strategy in use. Logged at startup.
  • Manifest World gains WorldVersionName, ChunkedSave, SaveNumber, FileSource, SaveFiles.

New ModImpact_Dump.json

  • Every loaded plugin plus any folder in [ModImpact] ScanPluginDirs / dump_eye scan=<dir> is read with Mono.Cecil; every member and type reference into a game assembly is resolved against the running build. Unresolved references list the plugin methods that use them.
  • [HarmonyPatch] attribute targets are checked: type-missing, method-missing, overload-missing, and ambiguous (a new overload appeared and no argument types were given).
  • References missing on disk but present in memory are reported as Bridged, with the Valheim10Compatibility bridge marker recognised.
  • Live Harmony patch map (HarmonyPatch index records) and a ModImpactSummary.
  • Client-only types are flagged as axis noise when scanning on a server, not counted as broken.

IL fingerprints

  • API_Dump.json types carry MethodBodies: a hash of each method's normalized IL (opcodes, resolved operand names, relative branch targets, locals, exception handlers). [API] ApiIlFingerprints.

Huginn's Report

  • Schema-aware: top-level fields present in only one side are excluded from the comparison and listed as SchemaAdded / SchemaRemoved per file. A 2.2.0 baseline diffs cleanly against 2.3.0.
  • API CHANGED records carry Members: Added, Removed, SignatureChanged, BodyChanged, TypeOnlyRipple (Vector2i/Vector2s, Int16/Int32 only), Renamed (same IL fingerprint), ValueChanged.
  • Huginn_Summary.json gains Breaking counters and the current dump's ModImpact summary.
  • New Huginn_Report.md: human-readable summary with breaking changes grouped by type, body-only changes, additions, registries by source, content, and the mod impact table with unresolved references ranked by plugin count. [Huginn] HuginnMarkdownReport.
  • ModImpact_Dump.json is keyed by plugin GUID / patch target.

ZDO keys

  • The key reverse map now hashes every string literal in the game and plugin assemblies, plus the _u / _i pair suffixes, so most #hash keys resolve. SectorIndex emitted on 0.221.13+.

Console

  • dump_eye scan=<dir> and noimpact.

Reference DLLs

  • libs-Tools/Mono.Cecil.dll (0.10.4.0, the copy BepInEx 5 loads) added for compile; not shipped.

Known limits (measured 2026-09-08)

  • ModImpact cannot see patch targets resolved by string (AccessTools.Method(typeof(X), "Name")) or by TargetMethod(); they show as Unchecked. Harmony's own log at PatchAll is the backstop.
  • A field whose type changed (0.221.13: VisEquipment.m_*Item string -> int, ZoneSystem.m_zones, ZDOMan.m_objectsByOutsideSector) cannot be bridged by any preloader; it is reported as unresolved and the only fix is in the mod. Bridged references are recognised by the Valheim10Compatibility bridge marker.
  • Renamed needs both dumps to carry MethodBodies, so it cannot fire against a 2.2.0 baseline.

2.2.0 — 2026-09-03 (pre-1.0 baseline release)

Provenance

  • New Manifest.json, written before any extractor runs: game version string with build hash, Steam buildid, md5 + size of every Managed DLL, BepInEx version and every loaded plugin, world name/seed/global keys, options used, and per-file results when the dump ends. Also bundled into the AgentML zip.

API dump rewritten

  • Full member surface per type: fields (with modifiers and constant values), properties (with accessor visibility), events, constructors, methods (full signatures with virtual / override / abstract), interfaces, attributes, nested types, enum values, Unity metadata.
  • Members are objects keyed by name so Huginn reports member-level adds and removes.
  • Only game assemblies by default ([API] ApiAssemblyFilter); compiler-generated types skipped.
  • Sequential, sorted by FullName. The old Parallel.ForEach made the file order random per run.

Huginn's Report rewritten as a structural diff

  • Every record is keyed on its identity; the report says ADDED, REMOVED and CHANGED per file, with flattened field-level deltas (old/new) for CHANGED and a Huginn_Summary.json of counts.
  • The baseline can be chosen: dump_eye baseline=<dir> or [Huginn] HuginnBaselineDir.
  • The old line-hash diff could not say "removed" and produced an 80 MB report of ADDED_OR_MODIFIED.

ZDO dump

  • Prefab hash resolved to a prefab name. Adds rotation, sector, persistence, object type, revisions, creation time, and every key/value from ZDOExtraData with hashes reverse-mapped through ZDOVars. Sorted by UID.
  • The ZNetScene active-area override is now off by default ([ZDO] ForceGlobalActiveArea). It forced the game to instantiate every ZDO in the world for the whole session and the dump never needed it on a host.

New Registry_Dump.json

  • Enums with values, ZDOVars hash table, console commands with cheat/server/admin flags, SpawnSystemList spawn tables, CreatureSpawner prefabs, environments and biome environments, random events, piece tables and every piece with requirements, skill definitions, and the full localization table.

Call graph

  • RpcRegistration index records: the RPC name string and the registering method for every ZNetView / ZRoutedRpc / ZRpc.Register call.
  • Types and the CalledBy index are sorted.

Determinism and hygiene

  • All output is UTF-8 without BOM (line splitters were dropping the first record).
  • Prefabs and ObjectDB items sorted by name; positions and floats in invariant round-trip format.
  • Localization now resolves (Localization lives in assembly_guiutils; the old reflective lookup asked assembly_valheim and 894 display names stayed as $tokens).

Console and automation

  • dump_eye options: baseline=<dir> nodiff noml nozdo noscene noloc; results print to the in-game console, not only the BepInEx log. New eye_status.
  • [Automation] AutoDumpOnWorldLoad / AutoDumpDelaySeconds / AutoDumpQuit for dedicated servers, which have no console to type into.

2.1.1

  • ValueExtractor (Values_Dump.json) and CallGraphExtractor (CallGraph_Dump.json) added.
  • Streaming JSON dump engine, AgentML zip bundle, F8/F9 IMGUI controls, line-hash Huginn's Report.

1.2.9

  • Fixed Readme file

1.2.8

  • Initial public release

Support Development

https://www.patreon.com/c/WubarrkDev