Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
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/OutsideActiveAreastaticness note inZDOExistencePatch.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, ...)becameFindSectorObjects(Vector2s, SimulationDistance, ...)andZoneSystem.m_activeArea/m_activeDistantAreawere 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. BuildShaperecords, as{Present, Shape}rows using type names (nevertypeof()on a type an older build may lack):ZDOMan.FindSectorObjects(arity and parameter types), theSimulationDistancestruct,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-tokenSectorApiclassification (pre-1.0 / 0.221.13 playtest / 1.0 release).ZDO.GetSectorIndex()now records its return type;ZNetScene.InActiveArea/OutsideActiveArearecord how many overloads are static. AbsentBuildShapemembers 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
TypeOnlyRipplecollapse still covers onlyVector2i/Vector2sandInt16/Int32. The(int, int) -> SimulationDistancechange 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 makingZNetScene.InActiveAreastatic.
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()(nowVector2s), the seven removedZDOExtraData.Get*s(ZDOID)readers (nowGetData(out ...)),World.m_worldVersion(now an enum) and theZNetScene.InActiveArea/OutsideActiveAreaoverloads are late-bound throughGameShape. A missing member costs one field, never an extractor. Three strategies for ZDO data (GetData,Get*s, private dictionaries).Manifest.jsonCompatibilitysection: every game member TheEye relies on, present or MISSING, plus the ZDO data strategy in use. Logged at startup.- Manifest
WorldgainsWorldVersionName,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 theValheim10Compatibility bridgemarker recognised. - Live Harmony patch map (
HarmonyPatchindex records) and aModImpactSummary. - Client-only types are flagged as axis noise when scanning on a server, not counted as broken.
IL fingerprints
API_Dump.jsontypes carryMethodBodies: 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/SchemaRemovedper 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.jsongainsBreakingcounters and the current dump'sModImpactsummary.- 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.jsonis 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/_ipair suffixes, so most#hashkeys resolve.SectorIndexemitted on 0.221.13+.
Console
dump_eye scan=<dir>andnoimpact.
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 byTargetMethod(); they show asUnchecked. Harmony's own log at PatchAll is the backstop. - A field whose type changed (0.221.13:
VisEquipment.m_*Itemstring -> 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 theValheim10Compatibility bridgemarker. Renamedneeds both dumps to carryMethodBodies, 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.ForEachmade 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.jsonof 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
ZDOExtraDatawith hashes reverse-mapped throughZDOVars. 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,
ZDOVarshash table, console commands with cheat/server/admin flags,SpawnSystemListspawn tables,CreatureSpawnerprefabs, environments and biome environments, random events, piece tables and every piece with requirements, skill definitions, and the full localization table.
Call graph
RpcRegistrationindex records: the RPC name string and the registering method for everyZNetView/ZRoutedRpc/ZRpc.Registercall.- Types and the
CalledByindex 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 (
Localizationlives inassembly_guiutils; the old reflective lookup askedassembly_valheimand 894 display names stayed as$tokens).
Console and automation
dump_eyeoptions:baseline=<dir> nodiff noml nozdo noscene noloc; results print to the in-game console, not only the BepInEx log. Neweye_status.[Automation] AutoDumpOnWorldLoad/AutoDumpDelaySeconds/AutoDumpQuitfor 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